代码之家  ›  专栏  ›  技术社区  ›  RBA

Delphi-计算目录大小api?

  •  3
  • RBA  · 技术社区  · 15 年前

    有人知道其他的方法来获得一个Directoy的大小,比计算它的大小通过计数文件与文件?我对一些win32 api函数感兴趣。我在谷歌上搜索过,但没有找到相关信息,所以我在这里询问。

    PS:我知道如何使用findfirst和findnext计算目录大小,并求和所有文件的大小。

    6 回复  |  直到 7 年前
        1
  •  4
  •   Cosmin Prund    15 年前

    获取一个目录的大小是一个相当大的问题,主要是因为它是您无法定义的。问题示例:

    • 一些文件系统,包括NTFS和Linux上的大多数文件系统都支持“硬链接”的概念。也就是说,相同的文件可能出现在多个地方。软链接(重分析点)也会产生同样的问题。
    • Windows允许将文件系统装载到目录。示例:“c:\drived”可能与“d:\”相同。
    • 您想要磁盘上的文件大小还是文件的实际大小?
    • 您关心实际的目录条目吗?它们也占据了空间!
    • 你如何处理你无法访问的文件?或者您没有浏览权限的目录?你数这些吗?

    考虑到所有这些意味着唯一可能的实现是递归实现。你可以自己写,或者希望你找到一个现成的,但最终的表现将是相同的。

        2
  •  2
  •   Chris Thornton    15 年前

    我不认为这有一个API。我认为Windows不知道答案。也就是说,它必须使用Marcelo指出的技术,递归地搜索树并总结每个文件夹。
    如果有这样一个API调用可用,那么其他东西也会使用它,Windows可以立即告诉您文件夹的大小。

        3
  •  2
  •   IceCold    8 年前

    我已经有了一个列出文件夹(和子文件夹)文件的功能,还有一个读取文件大小的功能。所以,我只写了一个小程序,把这两个结合起来。

    列表文件

    function ListFilesOf(CONST aFolder, FileType: string; CONST ReturnFullPath, DigSubdirectories: Boolean): TTSL;
    { If DigSubdirectories is false, it will return only the top level files,
      else it will return also the files in subdirectories of subdirectories.
      If FullPath is true the returned files will have full path.
      FileType can be something like '*.*' or '*.exe;*.bin'
      Will show also the Hidden/System files.
      Source Marco Cantu Delphi 2010 HandBook
    
       // Works with UNC paths}
    VAR
      i: Integer;
      s: string;
      SubFolders, filesList: TStringDynArray;
      MaskArray: TStringDynArray;
      Predicate: TDirectory.TFilterPredicate;
    
     procedure ListFiles(CONST aFolder: string);
     VAR strFile: string;
     begin
      Predicate:=
            function(const Path: string; const SearchRec: TSearchRec): Boolean
            VAR Mask: string;
            begin
              for Mask in MaskArray DO
                if System.Masks.MatchesMask(SearchRec.Name, Mask)
                then EXIT(TRUE);
              EXIT(FALSE);
            end;
    
      filesList:= TDirectory.GetFiles (aFolder, Predicate);
      for strFile in filesList DO
       if strFile<> ''                                                                                 { Bug undeva: imi intoarce doua intrari empty ('') }
       then Result.Add(strFile);
     end;
    
    begin
     { I need this in order to prevent the EPathTooLongException (reported by some users) }
     if aFolder.Length >= MAXPATH then
      begin
       MesajError('Path is longer than '+ IntToStr(MAXPATH)+ ' characters!');
       EXIT(NIL);
      end;
    
     if NOT System.IOUtils.TDirectory.Exists (aFolder)
     then RAISE Exception.Create('Folder does not exist! '+ CRLF+ aFolder);
    
     Result:= TTSL.Create;
    
     { Split FileType in subcomponents }
     MaskArray:= System.StrUtils.SplitString(FileType, ';');
    
     { Search the parent folder }
     ListFiles(aFolder);
    
     { Search in all subfolders }
     if DigSubdirectories then
      begin
       SubFolders:= TDirectory.GetDirectories(aFolder, TSearchOption.soAllDirectories, NIL);
       for s in SubFolders DO
         if cIO.DirectoryExists(s)                                                                     { This solves the problem caused by broken 'Symbolic Link' folders }
         then ListFiles(s);
      end;
    
     { Remove full path }
     if NOT ReturnFullPath then
      for i:= 0 to Result.Count-1 DO
       Result[i]:= TPath.GetFileName(Result[i]);
    end;
    

    获得文件化

    { Works with >4GB files
      Source: http://stackoverflow.com/questions/1642220/getting-size-of-a-file-in-delphi-2010-or-later }
    function GetFileSize(const aFilename: String): Int64;
    VAR
       info: TWin32FileAttributeData;
    begin
     if GetFileAttributesEx(PWideChar(aFileName), GetFileExInfoStandard, @info)
     then Result:= Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32)
     else Result:= -1;
    end;
    

    最后:

    function GetFolderSize(aFolder: string; FileType: string= '*.*'; DigSubdirectories: Boolean= TRUE): Int64;
    VAR
       i: Integer;
       TSL: TTSL;
    begin
     Result:= 0;
     TSL:= ListFilesOf(aFolder, FileType, TRUE, DigSubdirectories);
     TRY
      for i:= 0 to TSL.Count-1 DO
       Result:= Result+ GetFileSize(TSL[i]);
     FINALLY
      FreeAndNil(TSL);
     END;
    end;
    

    注意:
    1。您只能计算文件夹中某些文件类型的大小。例如,在包含BMP和JPEG文件的文件夹中,如果需要,只能获取BMP文件的文件夹大小。
    2。支持多种文件类型,如:' BMP; PNG’。
    三。您可以选择是否读取子文件夹的大小。

    进一步改进 :你可以大量 减小代码的大小 通过消除getfoldersize并将getfilesize直接移动到listfilesof。

    保证在Delphi Xe7上工作。

        4
  •  1
  •   Marcelo Cantos    15 年前

    如果您已经知道如何执行另一个级别,只需使用递归来获取每个级别。当函数遍历当前目录时,如果它遇到子目录,则递归调用该函数以获取该子目录的大小。

        5
  •  1
  •   Ted Stephens    15 年前

    您可以使用findfile组件。它将为您递归目录。

    http://www.delphiarea.com/products/delphi-components/findfile/

        6
  •  0
  •   Arch Brooks    9 年前

    以前的很多重复查找优先和查找下一个实现的例子都没有考虑更大的文件容量。这些例子不能产生正确的结果。一个能容纳更大文件容量的递归例程是可用的。

    {*-----------------------------------------------------------------------------
     Procedure: GetDirSize
     Author:    archman
     Date:      21-May-2015
     @Param     dir: string; subdir: Boolean
     @Return    Int64
     -----------------------------------------------------------------------------}
    
    function TBCSDirSizeC.GetDirSize(dir: string; subdir: Boolean): Int64;
    var
      rec: TSearchRec;
      found: Integer;
    begin
      Result := 0;
      if dir[Length(dir)] <> '\' then
        dir := dir + '\';
      found := FindFirst(dir + '*.*', faAnyFile, rec);
      while found = 0 do
      begin
        Inc(Result, rec.Size);
        if (rec.Attr and faDirectory > 0) and (rec.Name[1] <> '.') and
          (subdir = True) then
          Inc(Result, GetDirSize(dir + rec.Name, True));
        found := FindNext(rec);
      end;
      System.SysUtils.FindClose(rec);
    end;
    

    请访问下面的链接以获得完整的过程说明。 http://bcsjava.com/blg/wordpress/2015/06/05/bcs-directory-size-delphi-xe8/