Windows下保持目录结构的文件备份算法


Windows下保持目录结构的文件备份算法

作者:成晓旭


最近要做最一些数据处理工作,需要在大量的文件中,处理项目特定的文件数据库。由于文件数据库是散步在几百G的其他数据文件中,为便于进行数据库文件的备份,处理,写了一个简单的文件遍历、自动备份的小程序:确保备份之后的文件目录结构,与原来的目录结构完全一样,因为此文件的目录结构是项目的数据关系地图,关乎着很多重要的信息待后续进行分析、统计。

貌似Windows提供的文件复制API,不能自动创建目标文件的目录结构。本人比较懒惰,也没自己去研究这个问题,不知道是否还有其他的文件操作API,能够一步到位。如果有知道的朋友麻烦告诉一下。谢谢!


(其实,有一种体会:程序写的越久,胆子反而越小。大家会发现,下面所示的函数中,起实质性左右的代码往往还不及总代码行数的一半,另外的一大半代码,都是用于保护程序不要出错、检查边界、或者出于运行效率考虑



涉及到两个核心的处理过程。

其一,指定初始路径的文件遍历:

//从指定路径开始,遍历特定扩展名的文件

function TForm1.EnumFileInQueue(const strInitPath, fileExName: string;
var dwgDBFileBuffer: TStringBuffer; var dirNumber,
fileNumber: DWord): boolean;
const
Max_Buffer = $FFFF;
var
searchRec:TSearchRec;
found:Integer;
tmpStr,strMsg,strPath,strPathFile:String;
strTypeName,strBoxDir,strBoxCode,strFileName:string;
curDir:PChar;
dirs:TQueue;
begin
Result:=true;
fileNumber := 0;//查找结果(文件数)
dirNumber := 0;
dirs:=TQueue.Create;//创建目录队列
SetLength(dwgDBFileBuffer,0);
SetLength(dwgDBFileBuffer,Max_Buffer);
dirs.Push(Pointer(strInitPath));//将起始搜索路径入队
curDir:=dirs.Pop;//出队
while (curDir<> nil) do
begin
tmpStr:=StrPas(curDir)+'*.*';
//tmpStr:=StrPas(curDir)+'*.pdf';
//在当前目录查找第一个文件、子目录
//FillChar(searchRec,SizeOf(TSearchRec),'0');
//showLogToMemo(tmpStr);
found:=FindFirst(tmpStr,faAnyFile,searchRec);
while found=0 do
//找到了一个文件或目录后
begin
//如果找到的是个目录
if (searchRec.Attr and faDirectory)<>0 then
begin
if (searchRec.Name <> '.') and (searchRec.Name <> '..') then
begin
strPath := StrPas(curDir)+''+searchRec.Name+'\';
tmpStr := strPath;
dirs.Push(StrNew(PChar(tmpStr)));
Inc(dirNumber);
//strMsg := Format('%s',[strPath]);
showLogToMemo(searchRec.Name);
end;
end
//如果找到的是个文件
else
begin
//把找到的文件加到Memo控件
strPathFile := StrPas(curDir)+''+searchRec.Name;
//保存指定扩展名的文件
if Pos(fileExName,strPathFile) <> 0 then
begin
dwgDBFileBuffer[fileNumber] := strPathFile;
Inc(fileNumber);
if fileNumber >= Max_Buffer then break;
SetHintCaption(Format('load pdf File:%d',[fileNumber]));
end;
end;
//查找下一个文件或目录
found:=FindNext(searchRec);
end;
{当前目录找到后,如果队列中没有数据,则表示全部找到了;
否则就是还有子目录未查找,取一个出来继续查找。}
if dirs.Count > 0 then
curDir:=dirs.Pop
else
curDir:=nil;
Application.ProcessMessages();
if fileNumber >= Max_Buffer then break;
end;
//释放资源
dirs.Free;
FindClose(searchRec);
end;


其二:递归创建目录结构,并复制正确的文件到对应的目录:

//根据完整路径复制文件,如果目录不存在,则自动创建目录

function TForm1.CopyDBFileByCompletePath(const strFilePath: string): boolean;
const
Backup_Path_Name = 'backup';
var
strNewFile,strTempDir:string;
strHead,strTail:string;
pHead:integer;
begin
Result := false;
//判断参数
if NOT FileExists(strFilePath) then Exit;

pHead := Pos(STR_Dwg_Dat,strFilePath);
if (pHead > 0) then
begin
strHead := Copy(strFilePath,1,pHead-1);
strTail := Copy(strFilePath,pHead,Length(strFilePath));
end;
strNewFile := strHead + Backup_Path_Name + '\' + strTail;
strNewFile := ReplaceStr(strNewFile,'/','\');

strTempDir := ExtractFilePath(strNewFile);
if NOT DirectoryExists(strTempDir) then
begin
//递归创建目录结构
strTail := strNewFile;
strTempDir := '';
pHead := Pos('\',strTail);
while (pHead <> 0) do
begin
strHead := Copy(strTail,1,pHead);
strTail := Copy(strTail,pHead+1,Length(strTail));
strTempDir := strTempDir + strHead;
if NOT DirectoryExists(strTempDir) then
CreateDir(strTempDir);
pHead := Pos('\',strTail);
end;
end;
//强制复制文件,已存在的同名文件将被自动覆盖
Result := CopyFile(PWideChar(strFilePath),PWideChar(strNewFile),false);
end;

你可能感兴趣的:(源码,算法,windows)