使用C++17如何获取文件大小(以字节为单位)

100

有没有特定操作系统的陷阱,我应该知道的?

这个问题有很多重复(12345),但它们是几十年前回答的。在这些问题中,许多得到高票的答案今天已经是错误的。

来自其他(旧QA)的方法

  • stat.h(包装器sprintstatf),使用syscall

  • tellg(),根据定义返回位置但不一定是字节。返回类型不是int


4
Starter for 10: https://en.cppreference.com/w/cpp/header/filesystem起步:https://zh.cppreference.com/w/cpp/header/filesystem(译者注:Starter for 10是一个英国电视智力竞赛节目的一部分,意为“开始答题”,这里指开始翻译。)C++17中引入了一个新的标准库头文件<filesystem>,该头文件提供了一组类和函数,用于管理文件系统中的文件和目录。这些类和函数包括std::filesystem::path,它表示文件或目录的路径,并提供了许多有用的操作,例如连接、规范化和比较路径。std::filesystem::directory_entry表示文件系统中的一个实体,可以查询其属性(如大小和修改时间)和操作(如重命名和删除)。此外,还提供了许多其他类和函数,例如std::filesystem::file_size()std::filesystem::create_directory()。在使用<filesystem>之前,您需要确保编译器支持C++17,并在编译时链接正确的库(例如,在Windows上,您需要链接-lstdc++fs)。注意:<filesystem>是C++17的一部分,但在某些平台上可能不受支持。如果您需要在旧版本的C++或不支持<filesystem>的平台上编写代码,则可以使用第三方库,例如Boost.Filesystem。 - Richard Critten
5
@L.F.: 第一个问题已经被关闭,作为第二个问题的重复,这解释了为什么第一个问题中的被接受答案是错误的。第三个问题询问类似tellg的问题。唯一值得关注的是第四个问题,但那个问题不是很好,因为它在问题和回答中都过多地提到了ofstream。这个问题比其他问题更好地表达了意图(除了第一个有点奇怪被关闭的问题)。 - Nicol Bolas
6
请不要在您的问题和问题标题中添加无关信息。年份是无关紧要的,技术才是相关的。 - elixenide
2
stat(2) 到底有什么问题?它是不是已经过时了? - Lorinczy Zsigmond
1
@LorinczyZsigmond stat(2)有什么问题 它不是语言标准的一部分。 - Andrew Henle
显示剩余4条评论
2个回答

136

<filesystem>(在C ++17中添加)使得这个非常简单明了

#include <cstdint>
#include <filesystem>

// ...

std::uintmax_t size = std::filesystem::file_size("c:\\foo\\bar.txt");
如评论中所述,如果您计划使用此函数来决定从文件中读取多少字节,请记住,在您请求文件大小和尝试从文件中读取数据的时间之间,除非该文件是由您独占打开的,否则其大小可能会发生更改。

12
有没有一个世界,在那里 std::uintmax_t 能够保存比 std::size_t 更大的值?如果没有,为什么不使用更容易识别的 std::size_t?顺便赞一个答案。 - Fureeish
14
@Fureeish 我使用了 file_size 返回的类型,这只是因为它的返回类型如此。对我来说也有点奇怪。 - HolyBlackCat
42
std::size_t 只需要能够容纳内存中对象的最大尺寸。文件可以比内存对象大得多。 - Richard Critten
29
在32位Windows(我认为在大多数现代32位平台上)中,size_t是32位,而uintmax_t是64位。 - HolyBlackCat
16
文件系统是全局的,因此除非文件被 独占性地 打开,否则在您请求文件大小和读取数据之间,文件的大小可能会发生更改。 - Nicol Bolas
显示剩余18条评论

31

C++17带来了std::filesystem,它简化了许多与文件和目录相关的任务。你不仅可以快速获取文件大小、属性,还可以创建新目录、迭代文件、使用路径对象。

这个新库给我们提供了两个可用的函数:

std::uintmax_t std::filesystem::file_size( const std::filesystem::path& p );

std::uintmax_t std::filesystem::directory_entry::file_size() const;

第一个函数是std::filesystem中的一个自由函数,第二个函数是directory_entry中的一个方法。

每个方法都有多种重载形式,因为它可能会抛出异常或通过输出参数返回错误代码。下面是详细的代码,解释了所有可能的情况。

#include <chrono>
#include <filesystem>  
#include <iostream>

namespace fs = std::filesystem;

int main(int argc, char* argv[])
{
    try
    {
        const auto fsize = fs::file_size("a.out");
        std::cout << fsize << '\n';
    }
    catch (const fs::filesystem_error& err)
    {
        std::cerr << "filesystem error! " << err.what() << '\n';
        if (!err.path1().empty())
            std::cerr << "path1: " << err.path1().string() << '\n';
        if (!err.path2().empty())
            std::cerr << "path2: " << err.path2().string() << '\n';
    }
    catch (const std::exception& ex)
    {
        std::cerr << "general exception: " << ex.what() << '\n';
    }

    // using error_code
    std::error_code ec{};
    auto size = std::filesystem::file_size("a.out", ec);
    if (ec == std::error_code{})
        std::cout << "size: " << size << '\n';
    else
        std::cout << "error when accessing test file, size is: " 
              << size << " message: " << ec.message() << '\n';
}

2
这个“this”是什么?你能解释一下这段代码的用途,特别是当被采纳的答案使用的代码要少得多时? - Nico Haase
被接受的答案忽略了异常,当文件不存在时可能会抛出异常,这是相当常见的情况。 - Robert

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