So ermitteln Sie die Dateigröße in Bytes mit C ++ 17

97

Gibt es Fallstricke für bestimmte Betriebssysteme, die ich kennen sollte?

Es gibt viele Duplikate ( 1 , 2 , 3 , 4 , 5 ) dieser Frage, die jedoch vor Jahrzehnten beantwortet wurden. Die sehr hoch bewerteten Antworten in vielen dieser Fragen sind heute falsch.

Methoden von anderen (alten QS) auf .sx

  • stat.h (Wrapper sprintstatf ) verwendet syscall

  • tellg () gibt pro Definition eine Position zurück, aber nicht unbedingt Bytes . Der Rückgabetyp ist nicht int.

Jonas Stein
quelle
4
Starter für 10: en.cppreference.com/w/cpp/header/filesystem
Richard Critten
5
@LF: Nun, die erste Frage wurde als Duplikat der zweiten geschlossen, was erklärt, warum die akzeptierte Antwort in der ersten falsch ist . Der dritte fragt nach ähnlichen tellgProblemen. Das einzige, mit dem es sich zu beschäftigen lohnt, ist das vierte, und das ist nicht großartig, da es ofstreamsowohl in der Frage als auch in den Antworten zu viel darüber spricht . Dieser ist weitaus besser darin, die Absicht auszudrücken als die anderen (mit Ausnahme des ersten, der seltsamerweise geschlossen ist).
Nicol Bolas
6
Bitte fügen Sie Ihrer Frage und dem Fragentitel keine irrelevanten Informationen mehr hinzu. Das Jahr ist irrelevant; Die Technologien sind relevant.
Elixenid
2
Was ist überhaupt falsch stat(2)daran? Ist es zu alt geworden oder was?
Lorinczy Zsigmond
1
@ LorinczyZsigmond Was ist los mitstat(2) Es ist nicht Teil des Sprachstandards.
Andrew Henle

Antworten:

122

<filesystem>(hinzugefügt in C ++ 17) macht dies sehr einfach .

#include <cstdint>
#include <filesystem>

// ...

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

Wenn Sie diese Funktion verwenden möchten, um zu entscheiden, wie viele Bytes aus der Datei gelesen werden sollen, beachten Sie, wie in den Kommentaren erwähnt, dass ...

... wenn die Datei nicht ausschließlich von Ihnen geöffnet wird, kann ihre Größe zwischen dem Zeitpunkt, zu dem Sie danach fragen, und dem Zeitpunkt, zu dem Sie versuchen, Daten daraus zu lesen, geändert werden.
- Nicol Bolas

HolyBlackCat
quelle
11
Wenig offtopic: Gibt es eine Welt, in std::uintmax_tder man größere Werte halten kann als std::size_t? Wenn nicht, warum nicht verwenden std::size_t, was wohl besser erkennbar ist? +1 auf die Antwort, übrigens
Fureeish
13
@Fureeish Ich habe nur verwendet, weil das der Typ file_sizezurückgibt. Sieht für mich auch etwas komisch aus.
HolyBlackCat
39
@Fureeish std::size_tist nur erforderlich, um die maximale Größe von Speicherobjekten zu halten. Dateien können erheblich größer sein,
Richard Critten
26
@Fureeish Nun, unter 32-Bit-Windows (und ich nehme an, auf den meisten modernen 32-Bit-Plattformen) sind size_tes 32 Bit und uintmax_t64 Bit.
HolyBlackCat
16
@HolyBlackCat: Es wäre gut, etwas über die Tatsache zu sagen, dass das Dateisystem global ist. Wenn die Datei nicht ausschließlich von Ihnen geöffnet wird, kann ihre Größe zwischen dem Zeitpunkt, zu dem Sie danach fragen, und dem Zeitpunkt, zu dem Sie versuchen, Daten zu lesen, geändert werden davon.
Nicol Bolas
28

C ++ 17 bringt std::filesystemviele Aufgaben in Dateien und Verzeichnissen. Sie können nicht nur schnell die Dateigröße und ihre Attribute abrufen, sondern auch neue Verzeichnisse erstellen, Dateien durchlaufen und mit Pfadobjekten arbeiten.

Die neue Bibliothek bietet uns zwei Funktionen, die wir verwenden können:

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

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

Die erste Funktion ist eine freie Funktion in std::filesystem, die zweite ist eine Methode in directory_entry.

Jede Methode hat auch eine Überladung, da sie eine Ausnahme auslösen oder einen Fehlercode zurückgeben kann (über einen Ausgabeparameter). Unten finden Sie den Detailcode, in dem alle möglichen Fälle erläutert werden.

#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
quelle
2
Was ist das genau"? Können Sie erklären, wofür all dieser Code verwendet wird, insbesondere wenn die akzeptierte Antwort viel weniger Code verwendet?
Nico Haase