Как получить размер файла в байтах с помощью C ++ 17

97

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

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

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

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

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

Йонас Штайн
источник
4
Стартер для 10: en.cppreference.com/w/cpp/header/filesystem
Ричард Криттен,
5
@LF: Ну, первый вопрос был закрыт как дубликат второго, что объясняет, почему принятый ответ в первом неверен . Третий спрашивает о похожих tellgпроблемах. Единственный, над которым стоит возиться, - это четвертый, и он не очень хорош, так как он слишком много говорит ofstreamкак в вопросе, так и в ответах на него. Этот намного лучше выражает намерение, чем другие (за исключением первого, который на удивление закрыт).
Никол Болас
6
Пожалуйста, прекратите добавлять нерелевантную информацию к вашему вопросу и заголовку вопроса. Год не имеет значения; технологии актуальны.
elixenide 01
2
Что не так stat(2)? Он стал слишком старым или как?
Lorinczy Zsigmond 02
1
@LorinczyZsigmond Что не так?stat(2) Это не часть языкового стандарта.
Эндрю Хенле

Ответы:

123

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

#include <cstdint>
#include <filesystem>

// ...

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

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

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

СвятойЧерныйКошка
источник
11
Маленький оффтоп: есть ли в мире мир, где std::uintmax_tможно будет держать больше ценностей чем std::size_t? Если нет, почему бы не использовать std::size_t, что, возможно, более узнаваемо? +1 к ответу, кстати
Fureeish
13
@Fureeish Я использовал только потому, что тип file_sizeвозвращается. Мне тоже это выглядит немного странно.
HolyBlackCat
39
@Fureeish std::size_tтребуется только для хранения максимального размера объектов памяти. Файлы могут быть значительно больше,
Ричард Криттен,
27
@Fureeish Ну, в 32-битной Windows (и я предполагаю, что на большинстве современных 32-битных платформ) size_tэто 32 бита, а uintmax_tэто 64 бита.
HolyBlackCat
16
@HolyBlackCat: Было бы хорошо сказать что-то о том факте, что файловая система является глобальной, и поэтому, если файл не открывается исключительно вами, его размер может быть изменен между временем, когда вы его запрашиваете, и временем, когда вы пытаетесь прочитать данные. от него.
Никол Болас
28

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
Что такое «это»? Можете ли вы объяснить, для чего используется весь этот код, особенно когда в принятом ответе используется гораздо меньше кода?
Нико Хаасе