我需要比较两个目录的差异文件或文件夹,我知道需要递归检索目录下的所有文件,比较两个目录下相同文件的修改时间(LastWrite),但是我不知道应该怎么写才会效率,我给的函数原型:
procedure FindDifFilesFromTwoDir(FromDir,ToDir:string;DifFiles:Tstrings);
条件是:
1 两个目录须支持UNC,即网络路径,而且不能在两个目录内产生临时文件或临时文件夹(因为只读)
2 必须是快速的,有效率的,有人说在1分内可能检索10000万个文件!,我的要求只要1000个就行
procedure FindDifFilesFromTwoDir(FromDir,ToDir:string;DifFiles:Tstrings);
条件是:
1 两个目录须支持UNC,即网络路径,而且不能在两个目录内产生临时文件或临时文件夹(因为只读)
2 必须是快速的,有效率的,有人说在1分内可能检索10000万个文件!,我的要求只要1000个就行
sToDirectroyName: string; DifferentFiles: TStrings): Boolean;
var
hFindFile, toFindFile: Cardinal;
t, tfile: string;
sCurDir: string[255];
FindFileData, ToFileData: WIN32_FIND_DATA;
dtFindFile, dtToFindFile: TDateTime;
begin toFindFile := INVALID_HANDLE_VALUE;
//先保存当前目录 sCurDir := GetCurrentDir; ChDir(sFromDirectroyName); hFindFile := FindFirstFile('*.*', FindFileData);
if hFindFile <> INVALID_HANDLE_VALUE then //如果找到了文件
begin // if not DirectoryExists(sToDirectroyName) then
// ForceDirectories(sToDirectroyName); //目标目录不在就创建 repeat
Application.ProcessMessages;
tfile := FindFileData.cFileName; if (tfile = '.') or (tfile = '..') then
Continue; if FindFileData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY then
//如果文件是子目录
begin
t := sToDirectroyName + '\' + tfile; // not DirectoryExists(t) then //子目录不在就创建
// ForceDirectories(t); if sFromDirectroyName[Length(sFromDirectroyName)] <> '\' then
FindDifferentFilesBetweenTwoDirectory(sFromDirectroyName + '\' +
tfile, t, DifferentFiles)
else
FindDifferentFilesBetweenTwoDirectory(sFromDirectroyName + tfile,
sToDirectroyName + tfile, DifferentFiles)
end
else //如果是文件,这里是核心
begin
t := sToDirectroyName + '\' + tFile;
toFindFile := FindFirstFile(Pchar(t), ToFileData); //寻找目标文件
if toFindFile <> INVALID_HANDLE_VALUE then //如果在就比较时间
begin
//方式:转化为系统日期与时间作比较 新与旧,只有源文件是新的才复制
if GetFileLastModifyTime(findFileData.ftLastWriteTime, dtFindfile)
and GetFileLastModifyTime(toFileData.ftLastWriteTime, dttoFindfile)
and (dtfindFile > dtToFindFile) then
DifferentFiles.Add(GetCurrentDir + '\' + tFile);
end
else //如果目标目录没有该文件
DifferentFiles.Add(GetCurrentDir + '\' + tFile); end; //endif
//repeat end
until FindNextFile(hFindFile, FindFileData) = false; windows.FindClose(hFindFile);
windows.FindClose(ToFindFile); end
else //一个文件都没找到则
begin
ChDir(sCurDir);
Result := false;
exit;
end;
//回到原来的目录下
ChDir(sCurDir);
Result := True;
end;
共享只读?!那你怎么同步呢?通常这种同步,都是把本地的文件同步到远程啊,如果是只读的话,即使发现了不对,也不能修改远程的文件啊。分分太少了啊,这种代码是偏门,需要有人有兴趣和动力去写的,够呛有现成的。
转载--超级猛料
--------------------------------------------
procedure findall(disk,path: String; var fileresult: Tstrings);
var
fpath: String;
fs: TsearchRec;
begin
fpath:=disk+path+'\*.*';
if findfirst(fpath,faAnyFile,fs)=0 then
begin
if (fs.Name<>'.')and(fs.Name<>'..') then
if (fs.Attr and faDirectory)=faDirectory then
findall(disk,path+'\'+fs.Name,fileresult)
else
fileresult.add(disk+strpas(strupper(pchar(path)))+'\'+strpas(
strupper(pchar(fs.Name)))+'('+inttostr(fs.Size)+')');
while findnext(fs)=0 do
begin
if (fs.Name<>'.')and(fs.Name<>'..') then
if (fs.Attr and faDirectory)=faDirectory then
findall(disk,path+'\'+fs.Name,fileresult)
else
fileresult.add(disk+strpas(strupper(pchar(path)))+'\'+str
pas(strupper(pchar(fs.Name)))+'('+inttostr(fs.Size)+')');
end;
end;
findclose(fs);
end; procedure DoSearchFile(Path: string; Files: TStrings = nil);
var
Info: TSearchRec; procedure ProcessAFile(FileName: string);
begin
if Assigned(PnlPanel) then
PnlPanel.Caption := FileName;
Label2.Caption := FileName;
end; function IsDir: Boolean;
begin
with Info do
Result := (Name <> '.') and (Name <> '..') and ((attr and fadirectory) = fadirectory);
end; function IsFile: Boolean;
begin
Result := not ((Info.Attr and faDirectory) = faDirectory);
end;begin
Path := IncludeTrailingBackslash(Path);
try
if FindFirst(Path + '*.*', faAnyFile, Info) = 0 then
if IsFile then
ProcessAFile(Path + Info.Name)
else if IsDir then DoSearchFile(Path + Info.Name);
while FindNext(Info) = 0 do
begin
if IsDir then
DoSearchFile(Path + Info.Name)
else if IsFile then
ProcessAFile(Path + Info.Name);
Application.ProcessMessages;
if QuitFlag then Break;
Sleep(100);
end;
finally
FindClose(Info);
end;
end;
不如换个说法,有谁帮我把上面的代码做点优化或排错,因为速度一般般,另外有个致命BUG,我只需提取文件,它却有时加进文件夹,另外,对比较深层的文件夹,会出现没比较的情况!
支持unc,如果有用户名及密码,请在查询前执行net use命令,参看net use /?及delphi执行dos命令的方法。
TSearchRec,这里面有文件及目录的各种属性,可以用于比对!!!function TForm1.IsValidDir(SearchRec:TSearchRec):Boolean;
begin
//16为目录,与操作为16表示为一个目录
Result:=((SearchRec.Attr and 16)=16)
and (SearchRec.Name<>'.') and (SearchRec.Name<>'..');
end;function TForm1.SearchFile(MainPath:string;
var FoundResult:TStrings):Boolean;
var
i:integer;
Found:Boolean;
subdir1:TStrings;
searchRec:TsearchRec;
HasSubDir:Boolean;
begin
found:=false;
subdir1:=TStringList.Create;//字符串列表必须动态生成
//找出所有下级子目录。
HasSubDir := False; if (FindFirst(MainPath+'*.*', 4095, SearchRec)=0) then //4095指搜索全部
begin
if IsValidDir(SearchRec) then
begin
HasSubDir := True;
subdir1.Add(SearchRec.Name);
end;
while (FindNext(SearchRec) = 0) do
begin
if IsValidDir(SearchRec) then
begin
HasSubDir := True;
subdir1.Add(SearchRec.Name);
end;
end;
end;
FindClose(SearchRec); if (FindFirst(MainPath+'*.*',faAnyFile,SearchRec)=0) then
begin
found := True;
if (Not IsValidDir(SearchRec)) and (SearchRec.Name <> '.') and (SearchRec.Name <> '..')then
FoundResult.Add(MainPath+SearchRec.Name);
while (FindNext(SearchRec)=0) do
begin
if (Not IsValidDir(SearchRec)) and (SearchRec.Name <> '.') and (SearchRec.Name <> '..')then
FoundResult.Add(MainPath+SearchRec.Name);
end;
end;
FindClose(SearchRec); //这是递归部分,查找各子目录。
for i:=0 to subdir1.Count-1 do
found:=Searchfile(MainPath+subdir1.Strings[i]+
'\',foundresult) or found;
//资源释放并返回结果。
subdir1.Free;
result:=found;
end;procedure TForm1.Button5Click(Sender: TObject);
var
mStrList: TStrings;
mDate: TDateTime;
begin
mStrList := TStringList.Create;
mDate:=Now();
SearchFile('c:\windows\',mStrList);
Memo1.Lines.Clear;
Memo1.Lines.AddStrings(mStrList);
ShowMessage(Format('%d,%d',
[DateTimeToTimeStamp(now).Time-DateTimeToTimeStamp(mdate).Time
,mStrList.Count]));
end;着实花了我一番心血,怎么感谢我哩,呵呵。
http://www.codesky.net/showcode.asp?uid=36531
谢谢你的辛苦劳动!
But:
可是,上面的代码,只是找出某一目录下的所有文件夹与文件,存贮在字符串列表里,可是怎么没有对比的代码,
两个列表要如何对比,难道还要再生成一一对应的修改时间列表,然后一一对比,这样效率会优吗?只是两个列表由一列表找出另一列表是否存在相同文件就是个很麻烦的事!希望你可以再教教我!
我再把的思路说一下!
现在可以不先考虑UNC的支持,我们只要找出两个目录之间需要同步的文件列表!
条件是两个目录都是只读的!不可以生成目录,像我提供的代码就有这个BUG!如果不生成目录,会产生意想的后果,而且基本上很难调试(对我而言),我所知道的BUG,竟然会经常多出一些子目录,而且这些子目录也没有比较!
function TForm1.CompareFile(SearchRec:TSearchRec;CompPath:string):integer;
var
mResult: integer; //0:文件一致;1:目标目录无此文件;2:文件不一致
CompRec:TsearchRec;
begin
mResult := 1;
if (FindFirst(CompPath+SearchRec.Name,faAnyFile,CompRec)=0) then
begin
//可以在此增加其他判断条件
if (SearchRec.Size =CompRec.Size) then
mResult := 0
else
mResult := 2;
end;
Result := mResult;
end;function TForm1.IsValidDir(SearchRec:TSearchRec):Boolean;
begin
//16为目录,与操作为16表示为一个目录
Result:=((SearchRec.Attr and 16)=16)
and (SearchRec.Name<>'.') and (SearchRec.Name<>'..');
end;function TForm1.SearchFile(MainPath:string;CompPath:string;
var FoundResult:TStrings):Boolean;
var
i:integer;
Found:Boolean;
subdir1:TStrings;
searchRec:TsearchRec;
HasSubDir:Boolean;
begin
found:=false;
subdir1:=TStringList.Create;//字符串列表必须动态生成
//找出所有下级子目录。
HasSubDir := False; if (FindFirst(MainPath+'*.*', 4095, SearchRec)=0) then //4095指搜索全部
begin
if IsValidDir(SearchRec) then
begin
HasSubDir := True;
subdir1.Add(SearchRec.Name);
end;
while (FindNext(SearchRec) = 0) do
begin
if IsValidDir(SearchRec) then
begin
HasSubDir := True;
subdir1.Add(SearchRec.Name);
end;
end;
end;
FindClose(SearchRec); if (FindFirst(MainPath+'*.*',faAnyFile,SearchRec)=0) then
begin
found := True;
if (Not IsValidDir(SearchRec)) and (SearchRec.Name <> '.') and (SearchRec.Name <> '..')then
begin
i:=CompareFile(SearchRec,CompPath);
if i=1 then
FoundResult.Add(CompPath+SearchRec.Name+';无此文件')
else if i=2 then
FoundResult.Add(CompPath+SearchRec.Name+';文件不一致')
else
FoundResult.Add(CompPath+SearchRec.Name+';文件一致')
end;
while (FindNext(SearchRec)=0) do
begin
if (Not IsValidDir(SearchRec)) and (SearchRec.Name <> '.') and (SearchRec.Name <> '..')then
begin
i:=CompareFile(SearchRec,CompPath);
if i=1 then
FoundResult.Add(CompPath+SearchRec.Name+';无此文件')
else if i=2 then
FoundResult.Add(CompPath+SearchRec.Name+';文件不一致')
else
FoundResult.Add(CompPath+SearchRec.Name+';文件一致')
end;
end;
end;
FindClose(SearchRec); //这是递归部分,查找各子目录。
for i:=0 to subdir1.Count-1 do
found:=Searchfile(MainPath+subdir1.Strings[i]+
'\',CompPath+subdir1.Strings[i]+'\',foundresult) or found;
//资源释放并返回结果。
subdir1.Free;
result:=found;
end;procedure TForm1.Button5Click(Sender: TObject);
var
mStrList: TStrings;
mDate: TDateTime;
begin
mStrList := TStringList.Create;
mDate:=Now();
SearchFile('c:\gtja\','d:\gtja\',mStrList);
Memo1.Lines.Clear;
Memo1.Lines.AddStrings(mStrList);
ShowMessage(Format('%d,%d',
[DateTimeToTimeStamp(now).Time-DateTimeToTimeStamp(mdate).Time
,mStrList.Count]));
end;