开发者

Getting size of a file in Delphi 2010 or later?

开发者 https://www.devze.com 2022-12-09 22:30 出处:网络
Delphi 2010 has a nice set of new file access functions in IOUtils.pas (I especially like the UTC versions of the date-related functions). What I miss so far is something like

Delphi 2010 has a nice set of new file access functions in IOUtils.pas (I especially like the UTC versions of the date-related functions). What I miss so far is something like

TFile.GetSize (const Path : String)

What is the Delphi 2010-way to get the size of a file? Do I have to go back and use FindFirst to acces开发者_StackOverflow社区s TSearchRec.FindData?

Thanks.


I'm not sure if there's a "Delphi 2010" way, but there is a Windows way that doesn't involve FindFirst and all that jazz.

I threw together this Delphi conversion of that routine (and in the process modified it to handle > 4GB size files, should you need that).

  uses
    WinApi.Windows;

  function FileSize(const aFilename: String): Int64;
  var
    info: TWin32FileAttributeData;
  begin
    result := -1;

    if NOT GetFileAttributesEx(PWideChar(aFileName), GetFileExInfoStandard, @info) then
      EXIT;

    result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
  end;

You could actually just use GetFileSize() but this requires a file HANDLE, not just a file name, and similar to the GetCompressedFileSize() suggestion, this requires two variables to call. Both GetFileSize() and GetCompressedFileSize() overload their return value, so testing for success and ensuring a valid result is just that little bit more awkward.

GetFileSizeEx() avoids the nitty gritty of handling > 4GB file sizes and detecting valid results, but also requires a file HANDLE, rather than a name, and (as of Delphi 2009 at least, I haven't checked 2010) isn't declared for you in the VCL anywhere, you would have to provide your own import declaration.


Using an Indy unit:

uses IdGlobalProtocols;

function FileSizeByName(const AFilename: TIdFileName): Int64;


You can also use DSiFileSize from DSiWin32. Works in "all" Delphis. Internally it calls CreateFile and GetFileSize.

function DSiFileSize(const fileName: string): int64;
  var
    fHandle: DWORD;
  begin
    fHandle := CreateFile(PChar(fileName), 0, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if fHandle = INVALID_HANDLE_VALUE then
      Result := -1
    else try
      Int64Rec(Result).Lo := GetFileSize(fHandle, @Int64Rec(Result).Hi);
    finally CloseHandle(fHandle); end;
  end; { DSiFileSize }


I'd like to mention few Pure Delphi ways. Though i think Deltics made a most speed-effective answer for Windows platform, yet sometimes you want just rely on RTL and also make portable code that would work in Delphi for MacOS or in FreePascal/Virtual Pascal/whatever.


There is FileSize function left from Turbo Pascal days.

  • http://turbopascal.org/system-functions-filepos-and-filesize
  • http://docwiki.embarcadero.com/CodeExamples/XE2/en/SystemFileSize_(Delphi)
  • http://docwiki.embarcadero.com/Libraries/XE2/en/System.FileSize

The sample above lacks "read-only" mode setting. You would require that to open r/o file such as one on CD-ROM media or in folder with ACLs set to r/o. Before calling ReSet there should be zero assigned to FileMode global var.

  • http://docwiki.embarcadero.com/Libraries/XE2/en/System.FileMode

It would not work on files above 2GB size (maybe with negative to cardinal cast - up to 4GB) but is "out of the box" one.


There is one more approach, that you may be familiar if you ever did ASM programming for MS-DOS. You Seek file pointer to 1st byte, then to last byte, and check the difference.
I can't say exactly which Delphi version introduced those, but i think it was already in some ancient version like D5 or D7, though that is just common sense and i cannot check it.
That would take you an extra THandle variable and try-finally block to always close the handle after size was obtained.

  • Sample of getting length and such
  • http://docwiki.embarcadero.com/Libraries/XE2/en/System.SysUtils.FileOpen
  • http://docwiki.embarcadero.com/Libraries/XE2/en/System.SysUtils.FileSeek

Aside from 1st approach this is int64-capable. It is also compatible with FreePascal, though with some limitations

  • http://www.freepascal.org/docs-html/rtl/sysutils/fileopen.html

You can also create and use TFileStream-typed object - which was the primary, officially blessed avenue for file operations since Delphi 1.0

  • http://www.freepascal.org/docs-html/rtl/classes/tfilestream.create.html
  • http://www.freepascal.org/docs-html/rtl/classes/tstream.size.html
  • http://docwiki.embarcadero.com/Libraries/XE2/en/System.Classes.TFileStream.Create
  • http://docwiki.embarcadero.com/Libraries/XE2/en/System.Classes.TStream.Size

As a side note, this avenue is of course integrated with aforementioned IOUtils unit.

  • http://docwiki.embarcadero.com/Libraries/XE3/en/System.IOUtils.TFile.OpenRead


This is a short solution using FileSize that does the job:

function GetFileSize(p_sFilePath : string) : Int64;
var
  oFile : file of Byte;
begin
  Result := -1;
  AssignFile(oFile, p_sFilePath);
  try
    Reset(oFile);
    Result := FileSize(oFile);
  finally
    CloseFile(oFile);
  end;
end;

From what I know, FileSize is available only from XE2.


uses
  System.Classes, System.IOUtils;

function GetFileSize(const FileName : string) : Int64;
var
  Reader: TFileStream;
begin
  Reader := TFile.OpenRead(FileName);
  try
    result := Reader.Size;
  finally
    Reader.Free;
  end;
end;
0

精彩评论

暂无评论...
验证码 换一张
取 消