Comment obtenir la taille du fichier en octets avec C ++ 17

97

Y a-t-il des pièges pour des systèmes d'exploitation spécifiques, que je devrais connaître?

Il existe de nombreux doublons ( 1 , 2 , 3 , 4 , 5 ) de cette question, mais ils ont reçu une réponse il y a des décennies. Les réponses très votées à nombre de ces questions sont erronées aujourd'hui.

Méthodes d'autres (anciens QA) sur .sx

  • stat.h (wrapper sprintstatf ), utilise syscall

  • tellg () , renvoie par définition une position mais pas nécessairement des octets . Le type de retour ne l'est pas int.

Jonas Stein
la source
4
Starter pour 10: en.cppreference.com/w/cpp/header/filesystem
Richard Critten
5
@LF: Eh bien, la première question a été fermée comme un double de la seconde, ce qui explique pourquoi la réponse acceptée dans la première est fausse . Le troisième concerne des tellgproblèmes similaires . Le seul qui vaille la peine de s'embêter est le quatrième, et ce n'est pas génial, car il en parle trop ofstream, à la fois dans la question et dans ses réponses. Celui-ci est bien meilleur pour exprimer l'intention que les autres (sauf pour le premier, qui est étrangement fermé).
Nicol Bolas
6
Veuillez arrêter d'ajouter des informations non pertinentes à votre question et au titre de la question. L'année n'est pas pertinente; les technologies sont pertinentes.
elixenide
2
Quel est le problème de stat(2)toute façon? Est-il devenu trop vieux ou quoi?
Lorinczy Zsigmond
1
@LorinczyZsigmond Quel est le problème avecstat(2) Cela ne fait pas partie de la norme du langage.
Andrew Henle

Réponses:

123

<filesystem>(ajouté dans C ++ 17) rend cela très simple .

#include <cstdint>
#include <filesystem>

// ...

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

Comme indiqué dans les commentaires, si vous prévoyez d'utiliser cette fonction pour décider du nombre d'octets à lire dans le fichier, gardez à l'esprit que ...

... sauf si le fichier est exclusivement ouvert par vous, sa taille peut être modifiée entre le moment où vous le demandez et le moment où vous essayez d'en lire les données.
- Nicol Bolas

HolyBlackCat
la source
11
Petit hors-sujet: y a-t-il un monde où std::uintmax_tpourra porter de plus grandes valeurs que std::size_t? Si non, pourquoi ne pas utiliser std::size_t, qui est sans doute plus reconnaissable? +1 sur la réponse, btw
Fureeish
13
@Fureeish j'ai utilisé juste parce que c'est le type de file_sizeretour. Cela me semble un peu bizarre aussi.
HolyBlackCat
39
@Fureeish std::size_tne doit contenir que la taille maximale des objets en mémoire. Les fichiers peuvent être considérablement plus volumineux,
Richard Critten
26
@Fureeish Eh bien, sur Windows 32 bits (et je suppose sur la plupart des plates-formes size_t32 bits modernes), c'est 32 bits et uintmax_t64 bits.
HolyBlackCat
16
@HolyBlackCat: Il serait bon de dire quelque chose sur le fait que le système de fichiers est global, et donc à moins que le fichier ne soit exclusivement ouvert par vous, sa taille peut être modifiée entre le moment où vous le demandez et le moment où vous essayez de lire les données à partir de cela.
Nicol Bolas
28

C ++ 17 apporte std::filesystemce qui rationalise de nombreuses tâches sur les fichiers et les répertoires. Non seulement vous pouvez obtenir rapidement la taille du fichier et ses attributs, mais également créer de nouveaux répertoires, parcourir des fichiers, travailler avec des objets de chemin.

La nouvelle bibliothèque nous offre deux fonctions que nous pouvons utiliser:

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

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

La première fonction est une fonction libre dans std::filesystem, la seconde est une méthode dans directory_entry.

Chaque méthode a également une surcharge, car elle peut lever une exception ou renvoyer un code d'erreur (via un paramètre de sortie). Voici le code détaillé expliquant tous les cas possibles.

#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
la source
2
Qu'est-ce que «ceci» exactement? Pouvez-vous expliquer à quoi sert tout ce code, en particulier lorsque la réponse acceptée utilise beaucoup moins de code?
Nico Haase