Cómo obtener el tamaño del archivo en bytes con C ++ 17

97

¿Hay problemas para sistemas operativos específicos que debería conocer?

Hay muchos duplicados ( 1 , 2 , 3 , 4 , 5 ) de esta pregunta, pero fueron respondidos hace décadas. Las respuestas muy votadas en muchas de estas preguntas están equivocadas hoy.

Métodos de otros (antiguos controles de calidad) en .sx

  • stat.h (envoltorio sprintstatf ), usa syscall

  • tellg () , devuelve por definición una posición pero no necesariamente bytes . El tipo de devolución no lo es int.

Jonas Stein
fuente
4
Iniciador
Richard Critten
5
@LF: Bueno, la primera pregunta se ha cerrado como un duplicado de la segunda, lo que explica por qué la respuesta aceptada en la primera es incorrecta . El tercero pregunta por tellgproblemas similares . El único con el que vale la pena molestarse es el cuarto, y ese no es genial, ya que habla demasiado ofstream, tanto en la pregunta como en sus respuestas. Este es mucho mejor para expresar la intención que los demás (excepto el primero, que está extrañamente cerrado).
Nicol Bolas
6
Deje de agregar información irrelevante a su pregunta y al título de la pregunta. El año es irrelevante; las tecnologías son relevantes.
elixenide
2
¿Qué pasa con de stat(2)todos modos? ¿Ha envejecido demasiado o qué?
Lorinczy Zsigmond
1
@LorinczyZsigmond ¿Qué tiene de malo?stat(2) No es parte del estándar del lenguaje.
Andrew Henle

Respuestas:

123

<filesystem>(agregado en C ++ 17) hace que esto sea muy sencillo .

#include <cstdint>
#include <filesystem>

// ...

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

Como se señaló en los comentarios, si planea usar esta función para decidir cuántos bytes leer del archivo, tenga en cuenta que ...

... a menos que usted abra el archivo exclusivamente, su tamaño puede cambiarse entre el momento en que lo solicita y el momento en que intenta leer los datos del mismo.
- Nicol Bolas

SantoNegroGato
fuente
11
Little offtopic: ¿hay un mundo donde std::uintmax_tpodrá tener valores mayores que std::size_t? Si no es así, ¿por qué no usarlo std::size_t, que posiblemente sea más reconocible? +1 en la respuesta, por cierto
Fureeish
13
@Fureeish que usé solo porque ese es el tipo file_sizedevuelve. A mí también me parece un poco extraño.
HolyBlackCat
39
@Fureeish std::size_tsolo es necesario para contener el tamaño máximo de objetos de memoria. Los archivos pueden ser considerablemente más grandes,
Richard Critten
26
@Fureeish Bueno, en Windows de 32 bits (y supongo que en la mayoría de las plataformas modernas de 32 bits) size_tes de 32 bits y uintmax_tes de 64 bits.
HolyBlackCat
16
@HolyBlackCat: Sería bueno decir algo sobre el hecho de que el sistema de archivos es global y, por lo tanto, a menos que usted abra el archivo exclusivamente , su tamaño puede cambiarse entre el momento en que lo solicita y el momento en que intenta leer los datos. de eso.
Nicol Bolas
28

C ++ 17 trae lo std::filesystemque agiliza muchas tareas en archivos y directorios. No solo puede obtener rápidamente el tamaño del archivo, sus atributos, sino también crear nuevos directorios, iterar a través de archivos, trabajar con objetos de ruta.

La nueva biblioteca nos da dos funciones que podemos usar:

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

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

La primera función es una función libre en std::filesystem, la segunda es un método en directory_entry.

Cada método también tiene una sobrecarga, ya que puede generar una excepción o devolver un código de error (a través de un parámetro de salida). A continuación se muestra el código detallado que explica todos los casos posibles.

#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';
}
GOVIND DIXIT
fuente
2
¿Qué es exactamente "esto"? ¿Puede explicar para qué se usa todo este código, especialmente cuando la respuesta aceptada usa mucho menos código?
Nico Haase