![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Сравнение файлов
vasIZmax © (2007-09-20 10:33:00)Столкнулся с такой задачкой.
В папке порядка 17 000 файлов. Но среди них попадается большое количество дубликатов, т.е. полностью одинаковые, кроме имени. Как можно удалить дубликаты?
Думаю реализовывать так: через findfirst, findnext. Берем первый файл и начинаем сравнивать по-байтово(об этом тож сейчас думаю как реализовать) его со всеми по очередно. Если полностью схожи, то дубликат удаляем.
Но,имхо, такой метод будет очень долгим? Может по другому как?
Slym (2007-09-21 04:26:00) [1]5. "удаление" файлов в одну папку грозит потерей файлов с одним именем из разных подкаталАгов, останется один последний...
Slym (2007-09-21 04:18:00) [2]
procedure SeachDestroy(patch,path2,mask:string);
var
f1,fmain: TSearchRec;
SizeDir:int64;
begin
if testsize(patch,mask) then
begin
FindFirst(Patch+mask, faAnyFile, F1);
if (F1.name <> '') then
begin
fmain.Name:=f1.Name;
fmain.Size:=f1.Size;
while FindNext(F1) = 0 do
if (fmain.Size=f1.Size) then
begin
if CompareFiles(patch+fmain.name,patch+F1.name) then
deletefile(patch+f1.Name);
end;
end;
Movefile(patch+fmain.Name, path2);
FindClose(F1);
SeachDestroy(patch,path2,mask);
end;
end;
1. пропускаешь первый файл FindFirst и сразу FindNext (хотя первым идет сам каталог или его парент)
2. patch - обычно path :) хотя может по немецки както
3. в подкаталоги не заходишь? почему? и что за странная рекурсия внутри одного каталога - обычно рекурсия для подкаталогов, а у тебя внутри одной папки :)
нафига 2 FindFirst?
if testsize(patch,mask) then // превращается в FindFirst
begin
FindFirst(Patch+mask, faAnyFile, F1);
4. если рекурсия для "перемножения" файлов (а оно так и есть) то рекурсия "очень глубокая" получится как правильно заметил vasIZmax © (20.09.07 21:07) [36]
но
repeat
SeachDestroy(path,path2,mask);
until testsize(path,mask)=false
означает "пока все не 'загасишь', не возвращайся"?
vasIZmax (2007-09-20 21:07:00) [3]Да, и в указанном варианте от рекурсии надо уйти.
из procedureSeachDestroy(patch,path2,mask:string);удалить строкуSeachDestroy(patch,path2,mask);
и подправить
procedure TForm1.Button2Click(Sender: TObject);
var
Path,Path2,mask: string;
begin
Path := edit1.Text;
Path2:= edit2.Text;
mask:='*.gif';
repeat
SeachDestroy(path,path2,mask);
until testsize(path,mask)=false
end;
иначе переполнение стека при большом количестве файлов
Anatoly Podgoretsky (2007-09-20 20:39:00) [4]> vasIZmax (20.09.2007 20:34:34) [34]
> pFrom := PChar(fromDir + #0);
> pTo := PChar(files)
Почему во второй строке нет + #0
Добавь
vasIZmax (2007-09-20 20:34:00) [5]Значит вот что получилось, делал побайтово:-).
//перемещение файла
function MoveFile(const fromdir, files: string): Boolean;
var
fos: TSHFileOpStruct;
begin
ZeroMemory(@fos, SizeOf(fos));
with fos do
begin
wFunc := FO_MOVE;
fFlags := FOF_FILESONLY;
pFrom := PChar(fromDir + #0);
pTo := PChar(files)
end;
Result := (0 = ShFileOperation(fos));
end;
//сравнение
function CompareFiles(FirstFile, SecondFile: string): Boolean;
var
f1, f2: TMemoryStream;
begin
Result := false;
f1 := TMemoryStream.Create;
f2 := TMemoryStream.Create;
try
f1.LoadFromFile(FirstFile);
f2.LoadFromFile(SecondFile);
if f1.Size = f2.Size then
Result := CompareMem(f1.Memory, f2.memory, f2.Size);
finally
f2.Free;
f1.Free;
end
end;
//проверяю, не пуста ли папка
function TestSize(path,mask:string):boolean;
var
rec:tsearchRec;
begin
FindFirst(Path+mask, faAnyFile, rec);
if (rec.name <> '') then
result:=true
else
result:=false;
end;
//поиск дубликатов
procedure SeachDestroy(patch,path2,mask:string);
var
f1,fmain: TSearchRec;
SizeDir:int64;
begin
if testsize(patch,mask) then
begin
FindFirst(Patch+mask, faAnyFile, F1);
if (F1.name <> '') then
begin
fmain.Name:=f1.Name;
fmain.Size:=f1.Size;
while FindNext(F1) = 0 do
if (fmain.Size=f1.Size) then
begin
if CompareFiles(patch+fmain.name,patch+F1.name) then
deletefile(patch+f1.Name);
end;
end;
Movefile(patch+fmain.Name, path2);
FindClose(F1);
SeachDestroy(patch,path2,mask);
end;
end;
//использование
procedure TForm1.Button2Click(Sender: TObject);
var
Path,Path2,mask: string;
begin
Path := edit1.Text;
Path2:= edit2.Text;
mask:='*.gif';
SeachDestroy(path,path2,mask);
showmessage('All of files are treated');
end;
ЗЫ. вечерком посижу над crc
homm (2007-09-20 16:45:00) [6]> [24] Anatoly Podgoretsky © (20.09.07 15:27)
> Коллизии возможно, но мало вероятны, но если волную коллизии,
> то применить или CRC64 или MD5,
А не проще применить самый быстрый алгоритм (по логике CRC16) и каждое из 65536 ложных срабатываний проверить побайтово?
Anatoly Podgoretsky (2007-09-20 16:36:00) [7]> Jeer (20.09.2007 16:25:31) [31]
И я бы на его месте слабал бы простенькую программку анализа.
Jeer (2007-09-20 16:25:00) [8]Бум ждать:)
Anatoly Podgoretsky (2007-09-20 16:14:00) [9]> Jeer (20.09.2007 16:07:29) [29]
У него для этого есть благоприятные возможности, все 17000 файлов в одной папке, не надо заморачиваться рекурсией, сортировать надеюсь он умеет. Работы минут на 5, максимум 30.
Jeer (2007-09-20 16:07:00) [10]
> Anatoly Podgoretsky © (20.09.07 15:30) [26]
> Если же количество файлов одинаковой длины стремится к единице,
> то сравнение будет быстрее.
>
О чем и речь - все определяется статистикой файлов, их длиной и точками несовпадений при одинаковых длинах.
Это может только автор или специально поставленный эксперимент.:)
Sergey13 (2007-09-20 15:55:00) [11]> [25] Anatoly Podgoretsky © (20.09.07 15:28)
Ну и что, что моя программа работает на полчаса дольше? Я ее запущу на полчаса раньше и все.
(с) старый анекдот
8-)
Anatoly Podgoretsky (2007-09-20 15:31:00) [12]> Jeer (20.09.2007 14:44:23) [23]
Автор это легко может проверить, просканировав папку и посчитав процент совпадения длин.
Anatoly Podgoretsky (2007-09-20 15:30:00) [13]> Jeer (20.09.2007 14:18:20) [20]
Если бы не разовая работа для автора, то он бы мог написать тестовую задачу для сравнения времени. Если же количество файлов одинаковой длины стремится к единице, то сравнение будет быстрее.
Anatoly Podgoretsky (2007-09-20 15:28:00) [14]> Sergey13 (20.09.2007 14:14:19) [19]
На 17000 файлах и пофиг, дай бог если сравнит за несколько дней и то при условии оптимизировано алгоритма.
Anatoly Podgoretsky (2007-09-20 15:27:00) [15]> Jeer (20.09.2007 14:13:18) [18]
Коллизии возможно, но мало вероятны, но если волную коллизии, то применить или CRC64 или MD5, в любом случае это на порядки быстрее сравнения всех файлов одинаковой длины со всеми. За раз посчитали CRC в сортированом списке и разом удалили дубли.
Jeer (2007-09-20 14:44:00) [16]
> Slym © (20.09.07 14:29) [22]
А при чем тут HDD ?
Ситуация аналогична при размещении 17000 буферов в памяти. Стоимость операций compare квадратично, CRC линейна.
Очевидно, что в общем случае CRC выгоднее, но в частных случаях может быть оптимальнее Check_size + Compare .
Slym (2007-09-20 14:29:00) [17]Jeer © (20.09.07 14:13) [18]
это для памяти тесты...
а да HDD все по другому...
зависимость считанной с HDD информации (количество обращений к файлам)
(при условии равенства размера файлов)
CRC - n
Compare n^2/2
т.е при наличии 10 файлов равной длинны с отличием в последрем байте
имеем
CRC - 10, Compare - 50, т.е. разница в 5 раз
при 100 файлах - 100 и 5000 разница в 50 раз:)
Sergey13 (2007-09-20 14:29:00) [18]http://www.google.ru/search?hl=ru&q=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA+%D0%B4%D1%83%D0%B1%D0%BB%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D0%B2+%D1%84%D0%B0%D0%B9%D0%BB%D0%BE%D0%B2&lr=
дает дофига ссылок на готовые программы (на всякий случай).
Jeer (2007-09-20 14:18:00) [19]Разумеется - это для единичного сравнения.
При множественном сравнении все будет определятся соотношением совпавших и не совпавших, т.к. при несовпадении время Compare и статистически будет еще меньше, в какой-то момент вероятно наступит оптимум.
Учитывая, что первым пойдет тест на равенство размеров файла, полагаю, что все же Compare выиграет в итоге.
Sergey13 (2007-09-20 14:14:00) [20]> [0] vasIZmax © (20.09.07 10:33)
Это одноразовая работа или постоянная?
Если постоянная, то прикрутив к программе БД с запомненными CRC-шками можно достаточно легко автоматизировать процесс на 100%.
Если одноразово - ИМХО пофиг как сравнивать.