Как получить размер файла в байтах с С++ 17 - программирование

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

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

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

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

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

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

4b9b3361

Ответ 1

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

#include <cstdint>
#include <filesystem>

// ...

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

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

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

Ответ 2

С++ 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';
}

Ответ 3

Обратная совместимость со старыми операционными системами

Ваш вопрос предполагает, что в операционной системе установлены новейшие библиотеки C++. Это может быть не так.

В промышленном контексте нет ничего необычного в том, чтобы найти машины, которые работают изолированно от Интернета. Возможно, они либо не были обновлены, потому что обновление сложно сделать, либо им может быть запрещено обновляться, потому что ОС и связанные программы на ПК были проверены, и изменения потребуют повторной проверки. В любом случае, ПК не получает своих обновлений, и он вполне может застрять с библиотеками времени выполнения до C++ 17. Если ваше приложение предполагает, что библиотека времени выполнения существует и поддерживает это, оно может не запуститься.

Или в качестве другой альтернативы, вы можете по какой-либо причине использовать старую ОС, которая больше не поддерживается. Возможно, люди, работающие с этой вилкой Linux, разорились или просто прекратили ее обслуживать. Или, возможно, ОС устарела, и было принято сознательное решение не выпускать дальнейшие обновления. Какова бы ни была причина, если она стала не обслуживаемой до того, как C++ 17 библиотек времени выполнения стали широко доступными, снова возможно, что ваше приложение может не работать.

Очевидный путь к этому заключается в том, чтобы заранее указать, на каких платформах должно работать ваше приложение, и указать, что все обновления должны применяться. Если это Windows, что-либо до Windows 7, конечно, не рекомендуется, и для этого потребуются все обновления, чтобы использовать последние библиотеки времени выполнения. Если это Linux, посмотрите, где libstd C++ берет C++ 17. Также, если вы строите на этой платформе Linux вместо кросс-компиляции, посмотрите, где g++ становится полностью C++ 17-совместимым для платформы, потому что вам это тоже нужно.

Если вы работаете на другой ОС, такой как VxWorks, Tornado или FreeRTOS, вам снова придется искать все это для вашей ОС. Обычно встроенные ОС и связанные с ними библиотеки имеют тенденцию отставать от соответствия стандартам, потому что проверка для ОСРВ, как правило, более строгая.

Эта таблица перекрестных ссылок может быть полезна для определения версии поддерживаемого компилятора C++ 17.