Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.01.20;
Скачать: CL | DM;

Вниз

Сравнение двух файлов, очень медленно!   Найти похожие ветки 

 
SHS   (2004-01-06 13:31) [0]

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

procedure TfmMain.btCompareClick(Sender: TObject);
var
hFile: THandle;
File1, File2: file;
Byte1, Byte2: byte;
FSize, i: integer;
begin
if not (FileExists(Edit1.Text) and FileExists(Edit2.Text)) then
begin
MessageBoxA(Handle, "Please, select file to compare", "Error", MB_ICONSTOP);
Exit;
end;

fmMain.Cursor := crHourGlass;

hFile := CreateFile(PChar(Edit1.Text), 0, FILE_SHARE_READ,nil,OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE,0);
if hFile = INVALID_HANDLE_VALUE then
Exit;
FSize := GetFileSize(hFile, nil);

AssignFile(File1, Edit1.Text);
AssignFile(File2, Edit2.Text);
Reset(File1, 1);
Reset(File2, 1);

for i := 0 to FSize - 1 do
begin
Seek(File1, i);
Seek(File2, i);
BlockRead(File1, Byte1, 1);
BlockRead(File2, Byte2, 1);
if Byte1 <> Byte2 then
begin
with ListView.Items.Add do
begin
Caption:=IntToHex(i, 8);
SubItems.Add(IntToHex(Byte1, 2));
SubItems.Add(IntToHex(Byte2, 2));
end;
end;
Application.ProcessMessages;
end;

CloseFile(File1);
CloseFile(File2);

fmMain.Cursor := crDefault;
end;


 
alex_*** ©   (2004-01-06 13:35) [1]

считывать буфером, скажем по 4к, копить текстовую инфу и выкидывать ее через какое-то кол-во шагов или после сравнения.


 
Sandman25 ©   (2004-01-06 13:35) [2]

Лучше считывать и сравнивать не по одному байту.


 
Тимохов ©   (2004-01-06 13:36) [3]

Можно файлы считывать в память целиком и сравнивать уже там также побайтно.


 
SHS   (2004-01-06 13:37) [4]

Если сравнивать не по байтно, как я узнаю по какому адресу байты разные?


 
Sandman25 ©   (2004-01-06 13:39) [5]

[4] SHS (06.01.04 13:37)

Сравнив данный кусок еще раз, побайтно :)


 
SHS   (2004-01-06 13:41) [6]

Как считывать в память целиком, MapViewOfFile?


 
Sha ©   (2004-01-06 13:41) [7]

Считывать блоками (по 64к), сравнивать словами (тип cardinal или integer)


 
alex_*** ©   (2004-01-06 13:42) [8]

mem := TMemoryStream.Create();
mem.LoadFromFile(...);


 
Тимохов ©   (2004-01-06 13:43) [9]

Да тем же самым методом - которым вы считываеете, только не по одному байту - а весь файл сразу.

Определите длину файла.
Память берите через getmem.
Закачивайту сразу все. Не забудте BlockRead(File, P ^,...)
Сравнивайте в памяти.
Удаляйте freemem.

Все.


 
alex_*** ©   (2004-01-06 13:43) [10]

Надо вам с казать, господа, что основные тормоза, скорее всего, не из-за алгоритма сравнения, а из-за вывода в ListView после каждого байта.


 
Sha ©   (2004-01-06 13:44) [11]

И убери все связанное с hFile


 
Тимохов ©   (2004-01-06 13:44) [12]

alex_*** © (06.01.04 13:42) [8]
Лучший метод.
Но если все-таки делать BlockRead, то можно большему научиться, если конечно самообразование входит в ваши задачи.


 
Sha ©   (2004-01-06 13:45) [13]

alex_*** © (06.01.04 13:43) [10]
И это тоже


 
Sandman25 ©   (2004-01-06 13:45) [14]

[10] alex_*** © (06.01.04 13:43)

Тогда можно еще добавить LockWindowUpdate


 
SHS   (2004-01-06 13:47) [15]

Спасибо ВСЕМ большое за советы, буду пробовать, правда пока слабо во в этом разбираюсь :)


 
Sha ©   (2004-01-06 13:49) [16]

Seek(File1, i);
Seek(File2, i);
Application.ProcessMessages;


Это тоже лишнее


 
SHS   (2004-01-06 13:59) [17]

To alex_*** ©: В моём случае тормоза не из-за ListView, а в том, как я организовал сравнение, даже если файлы идентичны - всё это долго происходит.

To Sha ©: Убрал как вы подсказали, спасибо, но надо, видимо, ещё в сторону BlockRead идти, большими блоками считывать что ли...


 
raidan ©   (2004-01-06 14:02) [18]

Нда...
Где мои пятнадцать лет, где мои пятнадцать лет...


 
raidan ©   (2004-01-06 14:10) [19]

var f1,f2:file;
buffer1,buffer2:array[1..48*1024]of byte;
res1,res2:integer;
i:integer;
pos:integer;

<...........>

assignfile(f1,edit1.text);
assignfile(f2,edit2.text);
if filesize(f1)<>filesize(f2) then begin
//материться, что файлы не равны
exit;
end;
reset(f1,1);
reset(f2,1);
{$R-}
repeat
pos:=filepos(f1);
blockread(f1,buffer1,48*1024,res1);
blockread(f2,buffer2,48*1024,res2);

for i:=1 to res1 do begin
if buffer1[i]<>buffer2[i] then begin
//материться, что файлы не равны
//в байте pos+i-1, байт buffer1[pos+i-1] не равен buffer2[pos+i-1]
closefile(f2);
closefile(f1);
exit;
end;
end;

application.ProcessMessages;
until (res1=0) or (res2=0) or (res1<>res2);

closefile(f2);
closefile(f1);


 
raidan ©   (2004-01-06 14:11) [20]

Лениво писать лучший вариант с нормальными проверками и т.д. и т.п. :(


 
YuRock ©   (2004-01-06 14:23) [21]

> Тимохов © (06.01.04 13:43) [9]

Да тем же самым методом - которым вы считываеете, только не по одному байту - а весь файл сразу.


Интересно, а что будет, если файл, скажем, 3Гб? Ведь макс. кол-во памяти, которую может использовать программа - 2Гб!

Надо буффер делать! Килобайт по 20, например...


 
Sha ©   (2004-01-06 14:32) [22]

raidan © (06.01.04 14:10) [19]
"To use FileSize, the file must be open."


 
SHS   (2004-01-06 14:35) [23]

To raidan ©: Лучший вариант и не надо, с остальным я уже сам разберусь :) Работает - супер, скорость вообще обалденная, на то, что раньше выполнялось несколько секунд, уходят какие-то доли секунды! Поверить не могу :) Огромное спасибо за конкретный пример, очень благодарен. И спасибо ещё раз ВСЕМ, кто потратил время на разъяснение мне этого вопроса.


 
Тимохов ©   (2004-01-06 14:58) [24]

YuRock © (06.01.04 14:23) [21]
Ну уж знаете ли, тогда ответьте на вопрос, что будет если еть всего 1мб, но отличие в каждом байте? Не гикнется ли ListView?


 
Sandman25 ©   (2004-01-06 16:03) [25]

[24] Тимохов © (06.01.04 14:58)

Не ссорьтесь. Умная программа запросит размер файла, узнает, сколько памяти может ей выделить Windows и выберет наилучший алгоритм работы :)


 
ЮрийК ©   (2004-01-06 16:56) [26]

Лучше всего MapViewOfFile, думаю. Маппируешь два файла целиком и сравниваешь хоть побайтно, хоть словами или двойными словами даже.


 
alex_*** ©   (2004-01-06 17:12) [27]

для сравнения, я думаю, можно использовать CompareString(...). Там сделано оптимально, я надеюсь.


 
raidan ©   (2004-01-06 17:33) [28]


> Sha © (06.01.04 14:32) [22]
"To use FileSize, the file must be open."

Вполне быть может :)
Я еще не настолько крут, чтобы писать по-памяти без ошибок :)))



Страницы: 1 вся ветка

Текущий архив: 2004.01.20;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.017 c
14-63350
Pat
2003-12-30 01:48
2004.01.20
Программа просмотра сетевых пакетов


3-63026
BlackTiger
2003-12-21 22:38
2004.01.20
Глюки грида DeveloperExpress4? Или как?


4-63443
sds
2003-11-12 16:22
2004.01.20
Как заставить именованый pipe работать по сети?


1-63180
Эли
2004-01-10 14:36
2004.01.20
Вернуть активность форме


3-63003
Rio
2003-12-23 12:34
2004.01.20
Фильтрация данных