delphi - 计算目录大小API?

时间:2010-07-22 10:08:47

标签: windows winapi directory size delphi-7

任何人都知道以其他方式获得指数的大小,而不是通过计算文件与文件来计算它的大小?我对一些win32 API函数很感兴趣。我已经谷歌这个,但我没有找到相关信息,所以我在这里问。

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

6 个答案:

答案 0 :(得分:4)

获取一个目录的大小是一个非常大的问题,主要是因为它是你无法定义的。问题的例子:

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:2)

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

<强> ListFilesOf

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;

<强> GetFileSize

{ 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.支持多种文件类型,如下所示:&#39; .bmp; .png&#39;。
3.您可以选择是否要读取子文件夹的大小。

进一步改进:您可以通过消除GetFolderSize并将GetFileSize直接移动到ListFilesOf来大规模减小代码的大小

保证可以使用Delphi XE7。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:0)

以前的许多重复发现的示例首先找到并发现下一个实现不考虑更大的文件容量。这些例子没有产生正确的结果。可以使用容纳更大文件容量的递归例程。

{*-----------------------------------------------------------------------------
 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/