在C++中,如何在不打开文件的情况下检查文件大小?

14 浏览
0 Comments

在C++中,如何在不打开文件的情况下检查文件大小?

我正在尝试获取一个大文件(12GB+)的文件大小,我不想打开文件来获取大小,因为我认为这会消耗大量资源。有没有适用的API可以做到这一点?我使用的是Windows环境。

0
0 Comments

在C++中,想要在不打开文件的情况下检查文件大小,可以使用FindFirstFile函数。以下是使用该函数的示例代码:

#include "stdafx.h"
#include 
#include 
#include 
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;
}

解决方法是使用ULARGE_INTEGER代替手动操作ULONGLONG位,例如:`ULARGE_INTEGER ul; ul.LowPart = FindFileData.nFileSizeLow; ul.HighPart = FindFileData.nFileSizeHigh; ULONGLONG FileSize = ul.QuadPart;` 此外,Windows上的`%u`期望一个32位的无符号整数,所以对于64位整数,需要使用`%Lu`。

需要注意的是,FindFirstFile函数根据目录项中记录的文件大小来获取文件大小。但在某些情况下,这可能不准确,例如,如果文件是硬链接并且通过其他硬链接进行了修改,或者如果另一个应用程序打开并修改了该文件。有关更多信息,请参考[此链接](http://blogs.msdn.com/b/oldnewthing/archive/2011/12/26/10251026.aspx)。

需要注意的是,此方法对于符号链接不起作用,它会返回零。

0
0 Comments

最近我一直担心打开并关闭文件以获取文件大小所付出的代价。于是我决定查询性能计数器并看看这些操作到底有多昂贵。

下面是使用三种方法对同一文件进行文件大小查询所需的周期数。测试了两个文件:150MB和1.5GB。结果波动在10%左右,所以似乎不受实际文件大小的影响。(显然这取决于CPU,但它可以给你一个很好的参考点)

- 190个周期 - CreateFile, GetFileSizeEx, CloseHandle

- 40个周期 - GetFileAttributesEx

- 150个周期 - FindFirstFile, FindClose

可以从这个“高度科学的测试”中看出,最慢的是文件打开器。第二慢的是文件查找器,而获胜者是属性读取器。现在,就可靠性而言,CreateFile应该优于其他两个方法。但是,我仍然不喜欢打开文件只是为了读取其大小...除非我正在进行大小关键的操作,我会选择使用属性方法。

关于你的附言:当我有时间时,我会尝试读取正在打开并写入的文件的大小。但现在不是时候...

关于你的附言:实际上,GetFileAttributesEx()在其他进程仍在更新文件时确实返回了正确的文件大小,使其成为最快的(正确的文件大小)选择。如果它还有最后一次文件更改时间(不要与最后一次写入时间混淆),那么这个函数将是完美的!

你在上面的评论中提到的最后一次文件更改时间是什么?还有其他API可以获取这个时间吗?

这些数字看起来很棒,但我怀疑真正的问题是每种方法的IO有多少。在这方面它们是否不同还不清楚。

0
0 Comments

在C++中如何在不打开文件的情况下检查文件大小?

问题的出现原因是,用户需要在不打开文件的情况下获取文件的大小。用户认为打开文件是一项昂贵的操作,即使是一个12GB的文件也是如此。用户希望找到一种方法来避免打开文件但又能获取文件大小。

解决方法如下:

1. 使用GetFileSizeEx函数来获取文件的大小。这个函数比旧的GetFileSize函数更容易使用。需要通过调用CreateFile函数来打开文件,但这是一个廉价的操作。

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

2. 可以使用其他的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;
}

3. 如果在Visual Studio中编译,并且想避免调用Win32 API,可以使用_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会更快。它们可能会更快,但在没有测试之前你不会知道。

当然,如果在慢速存储介质上打开文件(如网络驱动器),CreateFile可能会非常慢,但慢是由于存储访问延迟,而不是文件的大小。

还可以通过调用FindFirstFile函数来读取文件的大小信息,而无需打开文件。

WIN32_FIND_DATA FindData;
HANDLE hFind = FindFirstFile(L"filename", &FindData);
if (hFind != INVALID_HANDLE_VALUE) {
    __int64 size = ((__int64)FindData.nFileSizeHigh) << 32 | FindData.nFileSizeLow;
    FindClose(hFind);
}

在不同的文件系统上可能会有性能问题,但在NTFS上,目录项中的文件大小可能不准确。

以上是在C++中不打开文件的情况下检查文件大小的方法。根据具体需求和文件系统的不同,选择适合的方法来获取文件大小。

0