Как получить размер файла в байтах с C ++ 17 - PullRequest
85 голосов
/ 30 июня 2019

Есть ли подводные камни для конкретных операционных систем, о которых я должен знать?

Существует множество дубликатов ( 1 , 2 , 3 , 4 , 5 ) этого вопрос, но они были даны ответы десятилетия назад. Очень многие проголосовавшие ответы на многие из этих вопросов сегодня неверны.

Методы из других (старых QA) на .sx

  • stat.h (оболочка sprintstatf ), использует системный вызов

  • tellg () , возвращает по определению a position , но не обязательно байты . Тип возврата не int.

Ответы [ 2 ]

113 голосов
/ 30 июня 2019

<filesystem> (добавлено в C ++ 17) делает это очень простым .

#include <cstdint>
#include <filesystem>

// ...

std::uintmax_t size = std::filesystem::file_size("c:\\foo\\bar.txt");

Как отмечалось в комментариях, если вы планируете использовать эту функцию для определения количества байтов для чтения из файла, имейте в виду, что ...

... если файл не открыт исключительно вами, его размер можно изменять между временем, когда вы запрашиваете его, и временем, когда вы пытаетесь прочитать данные из него.
- Никол Болас

26 голосов
/ 30 июня 2019

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';
}
...