2012-01-24 34 views
23

Tôi đang cố gắng để có được các tập tin của một tập tin lớn (12gb +) và tôi không muốn mở tập tin để làm như vậy là tôi giả định này sẽ ăn rất nhiều tài nguyên. Có API tốt để làm như vậy với? Tôi đang ở trong môi trường Windows.Kiểm tra tệp mà không cần mở tệp bằng C++?

Trả lời

1

Còn chức năng GetFileSize thì sao?

+2

Điều đó đòi hỏi phải mở tệp mà OP cho biết không mong muốn. –

+0

@remy nhưng tệp là nơi kích thước được lưu trữ để hai yêu cầu trong câu hỏi là mâu thuẫn –

+0

Thực ra không, bản thân tệp không lưu trữ kích thước. Hệ thống tập tin lưu trữ nó. 'GetFileSize()' yêu cầu tệp phải được mở trước, sau đó nó sử dụng tay cầm đó để xác định vị trí tệp nằm trong hệ thống tệp để nó có thể lấy kích thước. Nếu bạn sử dụng 'FindFirstFile()' thay vào đó, nó sẽ truy vấn hệ thống tập tin mà không cần mở tệp. –

41

Bạn nên gọi GetFileSizeEx dễ sử dụng hơn cũ hơn GetFileSize. Bạn sẽ cần phải mở tập tin bằng cách gọi CreateFile nhưng đó là một hoạt động giá rẻ. Giả định của bạn rằng việc mở một tệp là tốn kém, thậm chí một tệp 12GB, là sai.

Bạn có thể sử dụng chức năng sau đây để hoàn thành công việc:

__int64 FileSize(const wchar_t* name) 
{ 
    HANDLE hFile = CreateFile(name, GENERIC_READ, 
     FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
     FILE_ATTRIBUTE_NORMAL, NULL); 
    if (hFile==INVALID_HANDLE_VALUE) 
     return -1; // error condition, could call GetLastError to find out more 

    LARGE_INTEGER size; 
    if (!GetFileSizeEx(hFile, &size)) 
    { 
     CloseHandle(hFile); 
     return -1; // error condition, could call GetLastError to find out more 
    } 

    CloseHandle(hFile); 
    return size.QuadPart; 
} 

Có cuộc gọi API khác mà sẽ đưa bạn trở kích thước tập tin mà không buộc bạn phải tạo một tập tin xử lý, đặc biệt là GetFileAttributesEx. Tuy nhiên, nó hoàn toàn hợp lý rằng chức năng này sẽ chỉ mở tập tin đằng sau hậu trường.

__int64 FileSize(const wchar_t* name) 
{ 
    WIN32_FILE_ATTRIBUTE_DATA fad; 
    if (!GetFileAttributesEx(name, GetFileExInfoStandard, &fad)) 
     return -1; // error condition, could call GetLastError to find out more 
    LARGE_INTEGER size; 
    size.HighPart = fad.nFileSizeHigh; 
    size.LowPart = fad.nFileSizeLow; 
    return size.QuadPart; 
} 

Nếu bạn đang biên dịch với Visual Studio và muốn tránh gọi Win32 API thì bạn có thể sử dụng _wstat64.

Đây là một phiên bản _wstat64 dựa của hàm:

__int64 FileSize(const wchar_t* name) 
{ 
    __stat64 buf; 
    if (_wstat64(name, &buf) != 0) 
     return -1; // error, could use errno to find out more 

    return buf.st_size; 
} 

Nếu hiệu suất bao giờ trở thành một vấn đề cho bạn thì bạn nên thời gian tùy chọn khác nhau trên tất cả các nền tảng mà bạn nhắm mục tiêu để đạt được một quyết định. Đừng cho rằng các API không yêu cầu bạn gọi CreateFile sẽ nhanh hơn. Họ có thể là nhưng bạn sẽ không biết cho đến khi bạn đã hẹn giờ nó.

+0

Tất nhiên, ['CreateFile()' có thể khá chậm nếu bạn mở tệp trên phương tiện chậm] (http://blogs.msdn.com/b/larryosterman/archive/2004/05/24/140396. aspx) giống như các ổ đĩa mạng, nhưng sự chậm chạp sẽ là do độ trễ truy cập bộ nhớ và không phải do thực tế là tệp rất lớn. –

+0

@Insilico Hoặc ổ băng! Nhưng tôi tin rằng việc mở tệp là cách duy nhất để tìm kích thước tệp, ít nhất là trên các cửa sổ. –

+0

@DavidHeffernan: Không! Kích thước tệp nằm trong tiêu đề và do đó trong thư mục. FindFirstFile() như được hiển thị bên dưới sẽ đọc thông tin đó mà không phải mở tệp. –

9

Một tùy chọn khác bằng cách sử dụng chức năng FindFirstFile

#include "stdafx.h" 
#include <windows.h> 
#include <tchar.h> 
#include <stdio.h> 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    WIN32_FIND_DATA FindFileData; 
    HANDLE hFind; 
    LPCTSTR lpFileName = L"C:\\Foo\\Bar.ext"; 

    hFind = FindFirstFile(lpFileName , &FindFileData); 
    if (hFind == INVALID_HANDLE_VALUE) 
    { 
     printf ("File not found (%d)\n", GetLastError()); 
     return -1; 
    } 
    else 
    { 
     ULONGLONG FileSize = FindFileData.nFileSizeHigh; 
     FileSize <<= sizeof(FindFileData.nFileSizeHigh) * 8; 
     FileSize |= FindFileData.nFileSizeLow; 
     _tprintf (TEXT("file size is %u\n"), FileSize); 
     FindClose(hFind); 
    } 
    return 0; 

} 
+0

Sử dụng 'ULARGE_INTEGER' thay vì ghép các bit' ULONGLONG' theo cách thủ công, ví dụ: 'ULARGE_INTEGER ul; ul.LowPart = FindFileData.nFileSizeLow; ul.HighPart = FindFileData.nFileSizeHigh; ULONGLONG FileSize = ul.QuadPart; '. Ngoài ra, '% u' mong đợi một' không dấu int '32 bit trên Windows, bạn cần sử dụng'% Lu' thay cho một số nguyên 64 bit. –

+2

Tôi tin rằng FindFirstFile truy xuất kích thước tệp như được ghi trong mục nhập thư mục. Lưu ý rằng trong một số trường hợp, điều này có thể không chính xác, ví dụ: nếu tệp được liên kết cứng và được sửa đổi qua một liên kết cứng khác hoặc nếu một ứng dụng khác có tệp mở và đã sửa đổi tệp đó. Xem http://blogs.msdn.com/b/oldnewthing/archive/2011/12/26/10251026.aspx –

+1

Có lẽ vấn đề mà Harry chỉ ra là tại sao RTL Delphi ngừng sử dụng FindFirstFile trong hàm sys kích thước tệp của nó. –

23

Tôi cũng đã sống với nỗi sợ hãi của giá phải trả cho việc mở một tập tin và đóng nó chỉ để có được kích thước của nó. Và quyết định yêu cầu performance counter^ và xem các hoạt động thực sự tốn kém như thế nào.

Đây là số chu kỳ cần để thực hiện 1 truy vấn kích thước tệp trên cùng một tệp với ba phương pháp. Thử nghiệm trên 2 tệp: 150 MB và 1,5 GB. Có +/- 10% biến động để chúng dường như không bị ảnh hưởng bởi kích thước tệp thực. (rõ ràng điều này phụ thuộc vào CPU nhưng nó mang lại cho bạn một điểm thuận lợi tốt)

  • 190 chu kỳ - CreateFile, GetFileSizeEx, CloseHandle
  • 40 chu kỳ-GetFileAttributesEx
  • 150 chu kỳ - FindFirstFile, FindClose

The GIST with the code used^có sẵn tại đây.

Như chúng ta có thể thấy từ bài kiểm tra khoa học cao :) này, chậm nhất thực sự là công cụ mở tệp. 2 chậm nhất là công cụ tìm tệp trong khi người chiến thắng là trình đọc thuộc tính. Bây giờ, về độ tin cậy, CreateFile nên được ưa thích hơn khác 2. Nhưng tôi vẫn không thích khái niệm mở một tệp chỉ để đọc kích thước của nó ... Trừ khi tôi đang thực hiện các nội dung quan trọng, tôi ' sẽ chuyển đến các thuộc tính .

PS: Khi tôi có thời gian, tôi sẽ cố gắng đọc kích thước tệp được mở và đang ghi vào. Nhưng không phải ngay bây giờ ...

0

Kể từ C++ 17, có file_size là một phần của thư viện chuẩn. (Sau đó, người triển khai sẽ quyết định cách thực hiện nó hiệu quả!)

Các vấn đề liên quan