delphi - рассчитать размер каталога API? - PullRequest
3 голосов
/ 22 июля 2010

Кто-нибудь знает другой способ получить размер директои, кроме как рассчитать его размер, считая файл с файлом? Я заинтересован в некоторой функции Win32 API. Я гугл об этом, но я не нашел соответствующей информации, поэтому я спрашиваю здесь.

PS: я знаю, как рассчитать размер каталога с помощью findfirst и findnext и суммировать размер всего файла.

Ответы [ 6 ]

4 голосов
/ 22 июля 2010

Получение размера одного каталога - довольно большая проблема, в основном потому, что это то, что вы не можете определить. Примеры проблем:

  • Некоторые файловые системы, включая NTFS и большинство файловых систем в Linux, поддерживают понятие «жестких ссылок». То есть один и тот же файл может отображаться в нескольких местах. Мягкие ссылки (точки повторной обработки) создают ту же проблему.
  • Windows позволяет монтировать файловые системы в каталогах. Пример: «C: \ DriveD» может совпадать с «D: \».
  • Хотите ли вы размер файла на диске или фактический размер файла?
  • Вы заботитесь о реальных записях справочника? Они также занимают место!
  • Что вы делаете с файлами, к которым у вас нет доступа? Или каталоги, у которых нет разрешения на просмотр? Вы их считаете?

Учет всего этого означает, что единственно возможная реализация - это рекурсивная реализация. Вы можете написать свой или надеяться, что найдете готовый, но конечный результат будет таким же.

2 голосов
/ 10 августа 2017

У меня уже была функция для вывода списка файлов папки (и подпапок) и одна для чтения размера файла. Итак, я написал только небольшую процедуру, которая объединяет эти два.

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: /1213512/poluchit-razmer-faila-v-delphi-2010-ili-bolee-pozdnei-versii }
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'.
3. Вы можете выбрать, хотите ли вы читать или нет размер подпапок.

Дальнейшие улучшения : Вы можете значительно уменьшить размер кода , исключив GetFolderSize и переместив GetFileSize непосредственно в ListFilesOf.

Гарантированно работает на Delphi XE7.

2 голосов
/ 22 июля 2010

Я не думаю, что есть API для этого.Я не думаю, что Windows знает ответ.то есть он должен был бы рекурсивно искать в дереве и суммировать каждую папку, используя технику, указанную Марсело.
Если бы был доступен такой вызов API, то другие вещи также использовали бы его, и Windows могла бы немедленно сообщить вам папкуразмеры.

1 голос
/ 23 июля 2010

Вы можете использовать компонент FindFile.Он будет рекурсивным для вас.

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

1 голос
/ 22 июля 2010

Если вы уже знаете, как сделать другой уровень, просто используйте рекурсию, чтобы получить каждый уровень.Когда ваша функция пересекает текущий каталог, если он попадает в подкаталог, рекурсивно вызывайте функцию, чтобы получить размер этого подкаталога.

0 голосов
/ 18 августа 2016

Многие из предыдущих примеров повторного поиска сначала находят, и находят следующие реализации, не учитывающие большие объемы файлов. Эти примеры не дают правильных результатов. Доступна подпрограмма рекурсии, которая поддерживает большие объемы файлов.

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

...