检查filesize而不在c ++中打开文件?

时间:2012-01-24 17:20:50

标签: c++ windows winapi

我正在尝试获取大文件(12gb +)的文件大小,我不想打开文件这样做,因为我认为这会占用大量资源。有没有好的API可以这样做?我在Windows环境中。

5 个答案:

答案 0 :(得分:44)

您应该拨打GetFileSizeEx,这比旧的GetFileSize更容易使用。您需要通过调用CreateFile来打开文件,但这是一个便宜的操作。您打开文件很昂贵,甚至是12GB文件的假设是错误的。

您可以使用以下功能完成工作:

__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;
}

还有其他API调用会返回文件大小,而不会强制您创建文件句柄,尤其是GetFileAttributesEx。但是,这个函数只是在幕后打开文件是完全合理的。

__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;
}

如果您正在使用Visual Studio进行编译并且想要避免调用Win32 API,那么您可以使用_wstat64

以下是基于_wstat64的函数版本:

__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;
} 

如果性能成为您的问题,那么您应该在您定位的所有平台上计算各种选项,以便做出决定。不要认为不需要您调用CreateFile的API会更快。他们可能会,但在你计时之前你不会知道。

答案 1 :(得分:28)

我也生活在担心打开文件并关闭它以获得其大小的价格。并决定询问performance counter^并看看它有多昂贵操作真的是。

这是使用这三种方法在同一文件上执行1个文件大小查询所花费的周期数。在2个文件上测试:150 MB和1.5 GB。得到+/- 10%的波动,因此它们似乎不受实际文件大小的影响。 (显然这取决于CPU但它给你一个很好的有利位置)

  • 190个周期 - CreateFileGetFileSizeExCloseHandle
  • 40个周期 - GetFileAttributesEx
  • 150个周期 - FindFirstFileFindClose

The GIST with the code used^ 可在此处

从这个高度科学的:)测试可以看出,最慢的实际上是文件开启者。第二慢的是文件查找器,而获胜者是属性读取器。 现在,就可靠性而言,CreateFile应优先于其他2。但我仍然不喜欢打开文件的概念只是为了读取它的大小...除非我我正在做大小关键的事情,我会选择属性

PS 当我有时间时,我会尝试读取已打开并正在写入的文件的大小。但现在不是......

答案 2 :(得分:9)

使用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;

}

答案 3 :(得分:2)

从C ++ 17开始,file_size作为标准库的一部分。 (然后实现者决定如何有效地做到这一点!)

答案 4 :(得分:1)

GetFileSize功能呢?