Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Работа с потоками 
:(
    Опции темы
Antony41
Дата 26.4.2009, 18:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 332
Регистрация: 27.12.2008

Репутация: 1
Всего: 1



Вобщем проблема следующая:
Программа для поиска и удаления дубликатов файлов и использует такой способ:

Сначало выдаёт в список все запрошенные юсером файлы
1. File1
2. File2
3. File3
4. File4
5. File5

выполняет сравнение таким вот образом
Код

for I:=1 to 5 do
   for N:=I+1 to 5 do
      if File[I]=File[N] then //это образно на самом деле тут выполняется проверка на результат функции MyCompare
         //добавить в список дубликатов

пример функции MyCompare
function MyCompare(File1, File2:string):bool;
//далее идет загрузка File1 в Stream1, и File2 в Stream2
//далее чтение в масив байт, а потом сравнение 
Result:=CompareMem(@Buff1[0], @Buff2[0], кол-во байт);


и получается 
Код

for I:=1 to 5 do
   for N:=I+1 to 5 do
      if MyCompare(File[I], File[N]) then
         //добавить в список дубликатов



всё прекрасно, но...
если в списке 5 файлов, то MyCompare будет выполняться 10 раз,
если в списке 10 файлов, то MyCompare будет выполняться 45 раз,
если в списке 100 файлов, то MyCompare будет выполняться 4950 раз,
если в списке 7000 файлов, то MyCompare будет выполняться 24 496 500 раз.
формула (Count*Count+Count)/2-Count.

MyCompare использует 2 потока Stream1 и Stream2, то есть получается, что на 7000 файлов функция будет обращаться 24 496 500*2 раз к открытию файлов.

В память загрузить тоже не получиться. т.к. при каждом сравнении например File1 и File2, File1 и File3, позиция с которой читается файл1 в масив постоянно разная она зависит от размера file2 или file3 (файла с которым сравниваем) 
Код

A:=например 3;
////
var
fs1,fs2:TFileStream;
BaitToBait, pos:integer;
      {.....}
      begin
      fs2.Seek(Round(fs2.size/a+1), soFromBeginning);
      pos:=(FS2.Size-FS2.Position);
      fs1.Seek(-pos,  soFromEnd);
      BaitToBait:=Pos; //макс. значение загружаемых байт
      if BaitToBait>=Form2.DubleFrm1.sTrackBar2.Position then
         BaitToBait:=Form2.DubleFrm1.sTrackBar2.Position;
      end;
      {....}
fs1.ReadBuffer(buff1[0],BaitToBait);
fs2.ReadBuffer(buff2[0],BaitToBait);
Result:=CompareMem(@Buff1[0], @Buff2[0], BaitToBait);
////


для сравнения 7000 файлов получается примерно 10 часов smile 
как можно выполнить по другому не прибегая к такому невероятно огромному кол-ву открытия файлов или хотя бы выполнить этот процесс быстрее.

Дело в том что мне не просто нужно сравнить один файл с другим а у каждого файла сравнивается разная позиция и разным кол-вом байт
 smile
Результаты внушают=) через 10 часов=)
PM MAIL   Вверх
Лапоть
Дата 26.4.2009, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 185
Регистрация: 3.4.2009

Репутация: нет
Всего: 2



Или я чего-то не понял, но если файлы - разного размера, то зачем их сравнивать?
PM MAIL   Вверх
kami
Дата 26.4.2009, 19:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Можно попробовать сперва создать все FileStream и работать непосредственно с ними, а не с именами файлов.
Windows кеширует открытые файлы, поэтому повторный доступ к ним будет гораздо быстрее.
Правда, не знаю, как она отнесется к тысячам хендлов - где-то есть ограничение на их количество.

Можно убирать из списка файлы, которые признаны дубликатами. Цикл придется переделать на While или Repeat, но это не спасет, если нет дублирующихся файлов.
PM MAIL WWW   Вверх
RomanEEP
Дата 26.4.2009, 21:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 424
Регистрация: 18.5.2006
Где: Коломна

Репутация: 5
Всего: 8



Тебе нужно сперва посчитать CRC каждого файла - это линейная операция O(n). А затем в своей функции MyCompare() сперва сравниваешь CRC файлов и если они сошлись, то только тогда проводишь дополнительную проверку на содержании внутри.
PM MAIL   Вверх
Antony41
Дата 26.4.2009, 22:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 332
Регистрация: 27.12.2008

Репутация: 1
Всего: 1



Цитата(Лапоть @  26.4.2009,  18:46 Найти цитируемый пост)
Или я чего-то не понял, но если файлы - разного размера, то зачем их сравнивать?

Понимаешь НАПРИМЕР может быть две одинаковых песни, разные размером, без заголовков, Остаётся метод BaitToBait. Если одна песня или картинка, или что то еще меньшее размером, то это не значит что файлы не одинаковые, тут ты мне скажешь наоборот, но в том то и фишка, что все подобные проекты, работают, так: если файл и файл2 размером не равны, то перейти к следующему, а тут совсем не так.


Цитата(kami @  26.4.2009,  19:51 Найти цитируемый пост)
Можно попробовать сперва создать все FileStream и работать непосредственно с ними, а не с именами файлов.


Тоесть типа 
Код

var
fs: array[0..7000] of FileStream;?

не катит тут ты правильно сказал есть ограничение на кол-во
Выходит какая то ошибка что то вроде "недостаточно квот" по мойму
Пробовал но не помню точно.

Цитата(RomanEEP @  26.4.2009,  21:28 Найти цитируемый пост)
Тебе нужно сперва посчитать CRC каждого файла - это линейная операция O(n). А затем в своей функции MyCompare() сперва сравниваешь CRC файлов и если они сошлись, то только тогда проводишь дополнительную проверку на содержании внутри.


Crc это вроде бы как контрольные суммы, точно про них не знаю, но вроде, если файлы разные размером, то и контрольные суммы тоже будут разными?

Есть пример программы вот

Это сообщение отредактировал(а) Antony41 - 26.4.2009, 23:10
PM MAIL   Вверх
kami
Дата 26.4.2009, 23:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



1. В таком случае сохранять открытым хотя бы первый файл (т.е. File[i], переоткрывая только File[n]).
2. Взять AQTime (весьма полезная штука не только для этой задачи) и просмотреть, что же конкретно тормозит выполнение - открытие файла, чтение из него или сравнение. Где взять - не скажу, потому что сам взял не с официального источника smile

Добавлено через 1 минуту и 21 секунду
А еще лучше было бы сохранять открытым не первый файл, а его уже считанный буфер (если это возможно, код пробежал по диагонали).
PM MAIL WWW   Вверх
Antony41
Дата 27.4.2009, 09:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 332
Регистрация: 27.12.2008

Репутация: 1
Всего: 1



Цитата(kami @  26.4.2009,  23:05 Найти цитируемый пост)
А еще лучше было бы сохранять открытым не первый файл, а его уже считанный буфер (если это возможно, код пробежал по диагонали).


Цитата(Antony41 @  26.4.2009,  18:28 Найти цитируемый пост)
Дело в том что мне не просто нужно сравнить один файл с другим а у каждого файла сравнивается разная позиция и разным кол-вом байт

если позиция файла1 по соотношению к файлу2 была 5 000, и кол-во загружаемых байт 100 000, то если размер файла3 будет меньше, то и позиция файла1 при следующем чтении в поток будет другой.

получается,  остаётся вариант загрузить весь file1 в масив байт и сравнивать масив, тогда выолнение функции MyCompare станет быстрее в 2 раза, но только как загрузить весь файл в масив байт, а если это vob файл DVD фильма, и размер его 3,5-4,0 Гб.?
PM MAIL   Вверх
Christoph
Дата 27.4.2009, 11:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 667
Регистрация: 23.1.2008
Где: Харьков

Репутация: 1
Всего: 11



Код

function FilesAreEqual(const File1, File2: TFileName): Boolean;
const
  BlockSize = 100;
var
  fs1, fs2: TFileStream;
  L1, L2: Integer;
  B1, B2: array[1..BlockSize] of Byte;
begin
  Result := False;
  fs1 := TFileStream.Create(File1, fmOpenRead or fmShareDenyWrite);
  try
    fs2 := TFileStream.Create(File2, fmOpenRead or fmShareDenyWrite);
    try
      if fs1.Size = fs2.Size then
      begin
        fs1.Seek(2,soFromBeginning);
        fs2.Seek(2,soFromBeginning);
         while  fs1.Position < fs1.Size do
        begin
          L1 := fs1.Read(B1[1], BlockSize);
          L2 := fs2.Read(B2[1], BlockSize);
          if L1 <> L2 then
          begin
            Exit;
          end;
          if not CompareMem(@B1[1], @B2[1], L1) then Exit;
          end;
        Result := True;
      end;
    finally
      fs2.Free;
    end;
  finally
    fs1.Free;
  end;
end;


Такое не годиться? уже такое писал тебе...


--------------------
user posted image
PM MAIL ICQ   Вверх
Antony41
Дата 27.4.2009, 16:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 332
Регистрация: 27.12.2008

Репутация: 1
Всего: 1



Спасибо Christoph, именно с FilesAreEqual всё началось.
Но тут она не подходит
PM MAIL   Вверх
uranpro
Дата 28.4.2009, 18:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 571
Регистрация: 7.5.2008
Где: Moscow city

Репутация: нет
Всего: 1



Цитата(Antony41 @ 26.4.2009,  22:52)
Тоесть типа 
Код

var
fs: array[0..7000] of FileStream;?

не катит тут ты правильно сказал есть ограничение на кол-во
Выходит какая то ошибка что то вроде "недостаточно квот" по мойму

Код

  TGPoint=^TComplexGPoint;

  TComplexGPoint= record
    GInfo: FileStream;
    Next: TGPoint;
    end;

можно так на край)


--------------------
I want a perfect soul
PM MAIL ICQ   Вверх
kami
Дата 28.4.2009, 18:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Цитата(uranpro @  28.4.2009,  18:38 Найти цитируемый пост)
можно так на край)

Нельзя.
Тут дело не в размерности массива и не в связных списках (в этом плане гораздо лучше подойдут TList и TObjectList), а в количестве одновременно открытых хендлов. (хотя, опять-таки - я не нашел упоминания об ограничении на количество хендлов/файлов. Но это не значит, что его нет. По крайней мере - для GDI очень даже есть).
PM MAIL WWW   Вверх
Antony41
  Дата 28.4.2009, 20:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 332
Регистрация: 27.12.2008

Репутация: 1
Всего: 1



Спасибо Щас буду пробовать

Добавлено через 4 минуты и 56 секунд
Загрузить весь файл в один масив не получится, если он больше ОЗУ, наверное только потому.
PM MAIL   Вверх
kami
Дата 28.4.2009, 20:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Цитата(Antony41 @  28.4.2009,  20:16 Найти цитируемый пост)
если он больше ОЗУ, наверное только потому

ОЗУ тут ни при чем.
Адресное пространство, доступное процессу<>ОЗУ компьютера. Другое дело, что много выделишь - опухнет файл подкачки.
PM MAIL WWW   Вверх
MetalFan
Дата 29.4.2009, 14:05 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



Цитата(Antony41 @  26.4.2009,  22:52 Найти цитируемый пост)
понимаешь НАПРИМЕР может быть две одинаковых песни, разные размером, без заголовков, Остаётся метод BaitToBait. Если одна песня или картинка, или что то еще меньшее размером, то это не значит что файлы не одинаковые, тут ты мне скажешь наоборот

странная логика. на каком основании при побайтовом сравнении можно решить, что две "одинаковые" песни разного размера на самом деле одно и то же?!


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Antony41
Дата 30.4.2009, 16:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 332
Регистрация: 27.12.2008

Репутация: 1
Всего: 1



сравнить их кусок а не весь файл

Добавлено через 53 секунды
но конечно не с начала где лежат все заголовки
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0617 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.