2008-10-20 30 views

Trả lời

10

Just đối với grins ... bạn cũng có thể làm điều này với các luồng Chỉ hơn 2 dòng mã. Nói chung, tên tệp ứng dụng bao gồm đường dẫn cũng được lưu trữ trong Paramstr (0).

var 
    fs : tFilestream; 
begin 
    fs := tFilestream.create(paramstr(0),fmOpenRead or fmShareDenyNone); 
    try 
    result := fs.size; 
    finally 
    fs.free; 
    end; 
end; 
+0

Được thực hiện tốt. Tôi nghĩ câu trả lời của bạn dễ đọc hơn cả Mohammed Nasman hay bản thân tôi. – JosephStyons

2

Thật không may là không thể thực hiện điều đó chỉ bằng một hoặc hai dòng mã mà không sử dụng một số thư viện.

Phần dễ dàng là lấy tệp exe của ứng dụng. Bạn có thể tìm thấy nó trong Application.ExeName

Nói chung có nhiều khả năng để lấy kích thước tập tin:

  1. Mở tập tin và đọc kích thước của con suối. Điều này có thể được thực hiện bằng cách sử dụng chức năng Delphi 'cũ' FileOpenFileSize hoặc với TFileStream (sử dụng thuộc tính size) hoặc với chức năng API Win32 CreateFile và chức năng GetFileSize. (Phụ thuộc nền tảng!) Đảm bảo bạn mở tệp có quyền truy cập chỉ đọc.
  2. Trong môi trường Win32 thuần túy, bạn có thể sử dụng FindFirst để nhận kích thước tệp. Bạn có thể đọc nó từ TSearchRec.FindData.nFileSizeLow. Nếu bạn muốn chuẩn bị cho các tệp lớn hơn 2 GB (bạn nên), bạn phải sử dụng phần nFileSizeHigh.
  3. Trong Delphi.NET bạn có thể sử dụng System.IO.FileInfo, như thế này: FileInfo.Create(filename).Length (one-liner)
  4. Trong Linux, bạn có thể sử dụng chức năng lstat64 (Đơn vị Libc) và nhận được kích thước từ TStatBuf64.st_size. (hai lót nếu bạn không tính khai báo biến)

Trong JCL library bạn có thể tìm thấy nhiều chức năng hữu ích, bao gồm hàm đơn giản trả về kích thước tệp của tên tệp đã cho. (Nó sử dụng một phương pháp nào thích hợp với nền tảng nhất định)

+0

Tôi không biết tại sao điều này là câu trả lời đầu bình chọn. Bài đăng này chứa một số ví dụ về cách thực hiện việc này bằng cách sử dụng các lệnh VCL gốc Delphi. – JosephStyons

2

Bạn có thể thử này:

if FindFirst(ExpandFileName(Application.exename), faAnyFile, SearchRec) = 0 then 
    MessageDlg(Format('Tamaño: <%d>',[SearchRec.Size]), mtInformation, [mbOK], 0); 
    FindClose(SearchRec); 

===============
Neftali

+2

Hãy thử gói hai dòng đầu tiên trong một "try..finally", và đặt FindClose trong phần "cuối cùng". Điều đó đáng tin cậy hơn. – onnodb

2

Streams cũng có thể được sử dụng mà không có một biến TFileStream:

with TFilestream.create(paramstr(0), fmOpenRead or fmShareDenyNone) do 
    aFileSize := Size; 
    Free; 
end; 

Ugly, vâng.

Tôi thích sử dụng DSiFileSize từ DSiWin32. Nó sử dụng CreateFile nội bộ:

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 } 
5

Nó không nhỏ như bạn muốn, nhưng nó không cần xử lý. Tôi sử dụng điều này trong tất cả các trình lưu trữ và chương trình "SFX" của tôi phải biết kích thước của chúng. IIRC nó yêu cầu đơn vị Windows.

function GetExeSize: cardinal; 
var 
    p: pchar; 
    i, NumSections: integer; 
const 
    IMAGE_PE_SIGNATURE = $00004550; 
begin 
    result := 0; 
    p := pointer(hinstance); 
    inc(p, PImageDosHeader(p)._lfanew + sizeof(dword)); 
    NumSections := PImageFileHeader(p).NumberOfSections; 
    inc(p,sizeof(TImageFileHeader)+ sizeof(TImageOptionalHeader)); 
    for i := 1 to NumSections do 
    begin 
    with PImageSectionHeader(p)^ do 
     if PointerToRawData+SizeOfRawData > result then 
     result := PointerToRawData+SizeOfRawData; 
    inc(p, sizeof(TImageSectionHeader)); 
    end; 
end;
+0

Tại sao điều đó nên tốt hơn các cách tiếp cận khác? Không thiếu các tay cầm trong Windows ... – gabr

+1

Đơn giản. Trình xử lý đã được cấp phát, điểm 1 và thậm chí tốt hơn điều này cho bạn biết kích thước của ứng dụng ngay cả khi bạn có dữ liệu được thêm vào phía sau dữ liệu của ứng dụng. Điều này có thể cực kỳ quan trọng để biết! –

+0

Điểm thứ hai là hợp lệ, tôi đồng ý. – gabr

4

Để tương thích trong tương lai, bạn nên chọn triển khai không yêu cầu con trỏ hoặc chức năng API Windows khi có thể. Giải pháp dựa trên TFileStream do skamradt cung cấp có vẻ phù hợp với tôi.

Nhưng ... Bạn không nên lo lắng quá nhiều cho dù thường trình là 1 hoặc 10 dòng mã, vì bạn sẽ đóng gói nó trong một hàm lấy tên tệp làm tham số và trả về Int64, và đặt nó vào thư viện cá nhân của bạn về mã tái sử dụng. Sau đó, bạn có thể gọi nó như vậy:

GetMyFileSize (Application.ExeName);

0

Tôi muốn sửa đổi mã được cung cấp bởi skamradt, để làm cho nó hai dòng mã như bạn yêu cầu ;-)

with tFilestream.create(paramstr(0),fmOpenRead or fmShareDenyNone) do 
    ShowMessage(IntToStr(size)); 

nhưng tôi muốn sử dụng các mã như skamradt viết, bởi vì an toàn hơn

0

Ngắn nhất tôi có thể làm. Lưu ý rằng .Size là tính theo byte, vì vậy cho kilobyte, chia cho 1024.

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    with TFileStream.Create(Application.ExeName,fmShareDenyNone) do 
    ShowMessage(FloatToStr(Size/1024)); 
end; 

Check-out this link.

+0

Không chắc chắn lý do tại sao điều này biện minh cho một cuộc bỏ phiếu tiêu cực; ai đó có thể chỉ ra một vấn đề cụ thể với mã này? – JosephStyons

+2

Có thể là do bạn không giải phóng TFileStream một lần nữa. – Jeff

2
uses IdGlobalProtocols; 

var 
    ExeSize: Int64; 
begin 
    ExeSize := FileSizeByName(ParamStr(0)); 
    // or 
    ExeSize := FileSizeByName(Application.ExeName); 
end; 
Các vấn đề liên quan