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

来源:互联网 发布:淘宝客服统计销售额 编辑:程序博客网 时间:2024/06/03 18:05

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

作者:成晓旭


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

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


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


    完整源码已经上传到CSDN资源中心:http://download.csdn.net/detail/cxxsoft/4287500


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

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

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

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;