如何在C++中获取文件大小?

168

让我们创建一个补充问题,对应于这个。 什么是在C++中获取文件大小的最常见方法? 在回答之前,请确保它是可移植的(可以在Unix、Mac和Windows上执行),可靠、易于理解且没有库依赖(例如,不使用boost或qt,但可以使用glib,因为它是可移植的库)。


1
可能与https://dev59.com/iXE95IYBdhLWcg3wN7Kv重复。 - Eric Z
14
为什么不使用 Boost 而允许使用 Glib?Boost 也是可移植的。 - rve
3
“Portable”和“standard”意思不同。例如,Boost比标准C++更具可移植性,因为它可以解决编译器(包括旧版本)的非兼容性问题。在最严格的意义上,Fstat是可移植的。 - Thomas Edleson
1
@Thomas:没有标准就不可能有“可移植性”。这个标准可以是书面文件的形式(如POSIX或C++),你希望所有的实现都遵循它,或者它可以通过已经被移植到许多平台的通用实现来实现(包括大多数库,如Boost)。fstat()在POSIX中标准化,但Windows选择通过调用函数_fstat()来偏离该标准。fstat() 可移植的,因为你需要一个 #ifdef _WIN32 来使用它。 - Marc Mutz - mmutz
许多boost函数是可移植的,但需要明确编译。 - ABCD
//win32文件详情 ULONGLONG GetFileSizeAtt(const wchar_t *wFile) { WIN32_FILE_ATTRIBUTE_DATA fileInfo; ULONGLONG FileSize = 0ULL; //https://learn.microsoft.com/nl-nl/windows/win32/api/fileapi/nf-fileapi-getfileattributesexa?redirectedfrom=MSDN //https://learn.microsoft.com/nl-nl/windows/win32/api/fileapi/ns-fileapi-win32_file_attribute_data?redirectedfrom=MSDN if (GetFileAttributesEx(wFile, GetFileExInfoStandard, &fileInfo)) { ULARGE_INTEGER ul; ul.HighPart = fileInfo.nFileSizeHigh; ul.LowPart = fileInfo.nFileSizeLow; FileSize = ul.QuadPart; } return FileSize; } - BigChief
7个回答

172

10
根据 @jterm 的建议,打开流的方式应该是 std::ifstream in(filename, std::ios::binary | std::ios::ate); 为了让大家更轻松一些 ;) - jmpcm
5
函数返回后,该文件将被关闭。 - cfy
25
这篇回答解释了在SO上的一个问题,指出tellg函数不会报告文件的大小或相对于文件开头的偏移量(以字节为单位)。 - displayName
4
如上所述,我认为tellg()不能保证返回文件大小,尽管我在使用Linux系统时它总是这么做的(因此使用时需自行承担风险)。 - syntheticgio
8
此答案有误导性,因为无法将pos_type转换为int/long类型。 - Stepan Yakovenko
显示剩余10条评论

117

使用C++文件系统库:

#include <filesystem>

int main(int argc, char *argv[]) {
  std::filesystem::path p{argv[1]};

  std::cout << "The size of " << p.u8string() << " is " <<
      std::filesystem::file_size(p) << " bytes.\n";
}

23
值得注意的是,从C++17开始,filesystem已成为ISO C++标准。 - chappjc
3
那样比tellg更快吗? - Mohamad Elnaqeeb
3
我们真的需要先将文件名规范化吗? - Alexis Wilke
5
我认为这是最佳答案。 - tripulse
5
@MohamadElnaqeeb 刚刚在 g++8 上对此进行了基准测试;与 seekg 和 tellg 不同,它稍微快一些且正确。 - Fabian Keßler
显示剩余2条评论

116

虽然不一定是最受欢迎的方法,但我听说在某些情况下,使用 ftell、fseek 方法可能不会始终给出准确的结果。特别是,如果已经打开了一个文件,并且需要计算它的大小,而且此文件以文本文件的形式打开,那么它将给出错误的答案。

以下方法应始终起作用,因为 stat 是 Windows、Mac 和 Linux 上 c 运行库的一部分。

#include <sys/stat.h>

long GetFileSize(std::string filename)
{
    struct stat stat_buf;
    int rc = stat(filename.c_str(), &stat_buf);
    return rc == 0 ? stat_buf.st_size : -1;
}

or 

long FdGetFileSize(int fd)
{
    struct stat stat_buf;
    int rc = fstat(fd, &stat_buf);
    return rc == 0 ? stat_buf.st_size : -1;
}

如果您需要处理超过2GB的大文件,您可能想要调用stat64fstat64(如果可用)。


4
以上代码可在 C 和 C++ 中通用。 - hookenz
3
对于提到以二进制模式打开流的建议,我给出“+1”的支持。这解决了我在使用fseek()+ftell()计算大小并读取时遇到的问题。 - T.E.D.
12
我需要添加 #include <sys/stat.h>,这样 GetFileSize(...) 就可以正常工作了。 - syntheticgio
4
注意,在 Visual Studio 中,long 类型变量占据 4 个字节,因此你需要使用 long long 等类型来获取 Windows 上大文件的正确文件大小。 - zboson
这种方法适用于小于2GB的文件。 - thomas

30

你也可以使用fopen()、fseek()和ftell()函数来找出这个信息。

int get_file_size(std::string filename) // path to file
{
    FILE *p_file = NULL;
    p_file = fopen(filename.c_str(),"rb");
    fseek(p_file,0,SEEK_END);
    int size = ftell(p_file);
    fclose(p_file);
    return size;
}

4
不需要使用 <fstream><iostream>,但需要使用 <string> 并进行错误检查。(当使用空文件时, fseek 会崩溃,当出错时,ftell 返回 -1) - rve
4
初始化p_file并在下一行重写它是毫无意义的,并会导致许多静态代码分析工具报告“未使用的赋值”警告。 - Jens
5
图书馆实现允许不支持 SEEK_END(因此使用它的代码没有真正的标准可移植性)。 - stephen
1
相关链接:https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+不要使用fseek()+和ftell()+来计算常规文件的大小。 - rmobis
2
这个答案是误导性的,应该被降低评分:https://wiki.sei.cmu.edu/confluence/display/c/FIO19-C.+Do+not+use+fseek%28%29+and+ftell%28%29+to+compute+the+size+of+a+regular+file - itMaxence
显示剩余2条评论

9
#include <stdio.h>
int main()
{
    FILE *f;
    f = fopen("mainfinal.c" , "r");
    fseek(f, 0, SEEK_END);
    unsigned long len = (unsigned long)ftell(f);
    printf("%ld\n", len);
    fclose(f);
}

额外加分的是不完全沉迷于使用现代构造完成它的想法。 - Dino Dini

1

下面的代码片段完全回答了这篇帖子中的问题 :)

///
/// Get me my file size in bytes (long long to support any file size supported by your OS.
///
long long Logger::getFileSize()
{
    std::streampos fsize = 0;

    std::ifstream myfile ("myfile.txt", ios::in);  // File is of type const char*

    fsize = myfile.tellg();         // The file pointer is currently at the beginning
    myfile.seekg(0, ios::end);      // Place the file pointer at the end of file

    fsize = myfile.tellg() - fsize;
    myfile.close();

    static_assert(sizeof(fsize) >= sizeof(long long), "Oops.");

    cout << "size is: " << fsize << " bytes.\n";
    return fsize;
}

1
在C++中,您可以使用以下函数,它将返回文件的大小(以字节为单位)。
#include <fstream>

int fileSize(const char *add){
    ifstream mySource;
    mySource.open(add, ios_base::binary);
    mySource.seekg(0,ios_base::end);
    int size = mySource.tellg();
    mySource.close();
    return size;
}

这是行不通的,你不能将tellg输出转换为int。 - Stepan Yakovenko
1
@StepanYakovenko请查看此链接http://www.cplusplus.com/reference/istream/istream/tellg/。 - Hadi Rasekh
4
@HadiRasekh请停止使用cplusplus.com作为C++参考资料,它已经过时,无法使用。它不仅缺少来自C++14、C++17、C++20和实验性TS的新功能,某些文章中还存在相当大的错误 - bit2shift

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接