HOWTO · C++

So schreiben Sie in eine Datei in C++

Dieser Artikel zeigt, wie man in C++ in eine Datei schreibt. Erfahren Sie mehr über Dateistreams und die verschiedenen Dateimodi und sehen Sie sich klare Beispiele an, um Dateioperationen in Ihren C++-Programmen effektiv zu verwalten. Ob Sie Daten anhängen oder vorhandenen Inhalt überschreiben möchten – dieser Leitfaden hilft Ihnen weiter.

Auf dieser Seite

Verwenden Sie std::ofstream mit dem Einfügeoperator (<<), um gewöhnlichen Text in eine Datei zu schreiben. Öffnen Sie die Datei mit std::ios::app, um Daten anzuhängen, oder mit std::ios::trunc, wenn Sie den vorhandenen Inhalt ersetzen möchten. Wenn die Anzahl der Zeichen oder Bytes bekannt ist, können Sie die Memberfunktion write eines Streams verwenden; fwrite ist die entsprechende Alternative im C-Stil.

Dateistreams in C++ verstehen

Dateistreams verbinden ein C++-Programm mit einer Datei unter einem bestimmten Namen. Binden Sie <fstream> ein und erstellen Sie für die Ausgabe einen std::ofstream. Verwenden Sie std::fstream, wenn derselbe Stream sowohl für die Ein- als auch für die Ausgabe dienen soll. Der Einfügeoperator eignet sich für formatierten Text; ein Zeilenumbruch in der Zeichenfolge beginnt eine neue Zeile in der Datei. Prüfen Sie den Stream nach dem Öffnen und Schreiben: Auch ein plausibel wirkender Pfad kann unzugänglich sein, oder der Speicherplatz kann fehlen.

Führen Sie dieses Beispiel aus:

#include <fstream>
#include <iostream>

int main() {
    std::ofstream file("example.txt");
    if (!file) {
        std::cerr << "Could not open example.txt\n";
        return 1;
    }

    file << "Hello, C++!\n";
    file << "File output is ready.\n";
    file.close();
    if (!file) {
        std::cerr << "Could not finish writing example.txt\n";
        return 1;
    }

    std::cout << "Wrote example.txt\n";
    return 0;
}
Wrote example.txt

Die Meldung wird auf der Konsole ausgegeben; die beiden über file geschriebenen Zeilen stehen in example.txt. Öffnen Sie die Datei in einem Texteditor, um ihren Inhalt zu prüfen. Die englische Konsolenmeldung im unveränderten Beispiel bleibt englisch. Ein standardmäßig geöffneter, nur für die Ausgabe verwendeter std::ofstream erstellt die Datei, sofern das übergeordnete Verzeichnis vorhanden ist, und löscht beim Öffnen normalerweise einen bereits vorhandenen Dateiinhalt.

Dateien in verschiedenen Modi beschreiben

Der Öffnungsmodus bestimmt, was mit vorhandenen Daten geschieht. std::ios::app setzt jeden Schreibvorgang ans Dateiende und eignet sich daher für Protokolle oder Datensätze, die fortlaufend ergänzt werden sollen. Existiert die Datei noch nicht, kann das Öffnen zur Ausgabe sie erstellen, sofern Pfad und Berechtigungen dies zulassen. Das folgende eigenständige Beispiel schreibt eine Zeile im Anhängemodus; eine vorhandene example.txt ist dafür nicht erforderlich.

#include <fstream>
#include <iostream>

int main() {
    std::ofstream file("example.txt", std::ios::app);
    if (!file) {
        std::cerr << "Could not open example.txt\n";
        return 1;
    }

    file << "A new log entry\n";
    file.close();
    if (!file) {
        std::cerr << "Could not finish writing example.txt\n";
        return 1;
    }
    return 0;
}

Der bereitgestellte Laufzeittest wurde erfolgreich abgeschlossen und erzeugte keine Konsolenausgabe. Der Code schreibt A new log entry gefolgt von einem Zeilenumbruch. Enthält die Datei bereits Daten, wird die neue Zeile daran angehängt.

Dateien mit ios::trunc schreiben und überschreiben

std::ios::trunc verwirft beim Öffnen einer Datei deren bisherigen Inhalt. Wird ein std::ofstream zur Ausgabe ohne std::ios::app geöffnet, wird die Datei normalerweise ebenfalls geleert. Geben Sie std::ios::trunc an, wenn Sie dieses Verhalten ausdrücklich festlegen möchten. Verwenden Sie keine dieser Varianten, wenn die alten Daten erhalten bleiben müssen.

#include <fstream>
#include <iostream>

int main() {
    std::ofstream file("example.txt", std::ios::trunc);
    if (!file) {
        std::cerr << "Could not open example.txt\n";
        return 1;
    }

    file << "Current report\n";
    file.close();
    if (!file) {
        std::cerr << "Could not finish writing example.txt\n";
        return 1;
    }
    return 0;
}

Der bereitgestellte Laufzeittest wurde erfolgreich abgeschlossen und erzeugte keine Konsolenausgabe. Der Code schreibt nur Current report und einen Zeilenumbruch in example.txt und ersetzt damit den bisherigen Inhalt.

Mit fstream::write in eine Datei schreiben

Verwenden Sie die Stream-Memberfunktion write, wenn die Daten bereits in einem Zeichenpuffer vorliegen und ihre Länge bekannt ist. Die Funktion erwartet einen Zeiger auf Zeichen sowie die Anzahl der zu schreibenden Zeichen; einen Abschluss oder Zeilenumbruch fügt sie nicht selbst hinzu. Der zweite Parameter hat den Typ einer Streamgröße. Mit data.size() werden daher die gespeicherten Zeichen der Zeichenfolge geschrieben, ohne ein abschließendes Nullzeichen einzubeziehen. Prüfen Sie nach dem Aufruf den Streamstatus, um einen fehlgeschlagenen Schreibvorgang zu erkennen. Die Schnittstelle wird in der cppreference-Dokumentation zu basic_ostream::write beschrieben.

#include <fstream>
#include <iostream>
#include <string>

int main() {
    const std::string data = "C++ buffer data\n";
    std::fstream file("buffer.txt", std::ios::out | std::ios::trunc);
    if (!file) {
        std::cerr << "Could not open buffer.txt\n";
        return 1;
    }

    file.write(data.data(), static_cast<std::streamsize>(data.size()));
    if (!file) {
        std::cerr << "Could not write buffer.txt\n";
        return 1;
    }
    file.close();
    if (!file) {
        std::cerr << "Could not finish writing buffer.txt\n";
        return 1;
    }
    return 0;
}

Der bereitgestellte Laufzeittest wurde erfolgreich abgeschlossen und erzeugte keine Konsolenausgabe. Der Code schreibt die Zeichen aus data in buffer.txt. Der Zeilenumbruch gehört zur Zeichenfolge; ein abschließendes Nullzeichen wird nicht geschrieben.

Zeichenorientiertes und byteorientiertes Schreiben unterscheiden sich darin, ob die Daten formatiert werden. Der Einfügeoperator wandelt Werte in Text um, während write und fwrite die Bytes des Puffers ohne Formatierung kopieren. Das bloße Kopieren der Bytes garantiert allein noch nicht, dass sie unverändert in der Datei ankommen: Ein im Textmodus geöffneter Stream kann Zeilenumbruchzeichen auf Plattformen mit abweichendem Zeilenende trotzdem übersetzen, etwa wenn Windows \n bei der Ausgabe in \r\n umwandelt. Wenn die exakten Bytes wichtig sind, öffnen Sie den Stream im Binärmodus, zum Beispiel mit std::ios::out | std::ios::binary | std::ios::trunc, oder übergeben Sie fopen statt "w" den Modus "wb", damit keine Übersetzung stattfindet.

Mit der C-Funktion fwrite in eine Datei schreiben

Für Datei-E/A im C-Stil erwartet fwrite einen Zeiger, die Elementgröße, die Anzahl der Elemente und einen FILE*. Der Rückgabewert gibt die Anzahl der geschriebenen Elemente an, nicht die Bytezahl – außer die Größe jedes Elements beträgt eins. Prüfen Sie diesen Wert, schließen Sie dann die Datei und kontrollieren Sie auch den Rückgabewert von fclose, da gepufferte Schreibfehler erst beim Schließen auftreten können.

#include <cstdio>
#include <cstring>
#include <iostream>

int main() {
    const char data[] = "C file output\n";
    const std::size_t size = std::strlen(data);
    std::FILE* file = std::fopen("c-output.txt", "w");
    if (file == nullptr) {
        std::cerr << "Could not open c-output.txt\n";
        return 1;
    }

    const std::size_t written = std::fwrite(data, 1, size, file);
    const int close_status = std::fclose(file);
    if (written != size || close_status != 0) {
        std::cerr << "Could not finish writing c-output.txt\n";
        return 1;
    }
    return 0;
}

Der bereitgestellte Laufzeittest wurde erfolgreich abgeschlossen und erzeugte keine Konsolenausgabe. Der Code schreibt die Zeichen aus data einschließlich des Zeilenumbruchs in c-output.txt. Der Modus "w" erstellt die Datei oder löscht ihren bisherigen Inhalt.

Fazit

Für gewöhnlichen Text eignen sich std::ofstream und <<. Wählen Sie std::ios::app, um den alten Inhalt zu behalten und neue Daten anzuhängen, oder std::ios::trunc, um ihn zu ersetzen. Verwenden Sie write für einen Puffer bekannter Länge und fwrite für E/A im C-Stil. Prüfen Sie den Status nach dem Öffnen und Schreiben sowie mögliche Fehler beim Schließen, wenn das Programm feststellen muss, ob alle Daten geschrieben wurden.

Häufig gestellte Fragen

  1. Woran erkenne ich, ob eine Datei geöffnet wurde? Prüfen Sie den Stream direkt (if (!file)) oder rufen Sie unmittelbar nach dem Öffnen is_open() auf. Behandeln Sie einen Fehler, bevor Sie zu schreiben beginnen.

  2. Wie kann ich Daten anhängen, ohne den vorhandenen Inhalt zu ersetzen? Öffnen Sie einen Ausgabestream mit std::ios::app. Jeder Schreibvorgang wird ans Dateiende geleitet.

  3. Erstellt C++ eine Datei, die noch nicht existiert? Ausgabestreams und fopen mit dem Modus "w" können eine Datei erstellen, sofern das übergeordnete Verzeichnis vorhanden ist und der Prozess über die nötigen Berechtigungen verfügt. Fehlt das Verzeichnis oder reichen die Berechtigungen nicht aus, schlägt das Öffnen fehl.

  4. Wie schreibe ich mehrere Zeilen? Fügen Sie mit << Zeilenumbruchzeichen ein oder nehmen Sie sie in den an write übergebenen Puffer auf. Weder write noch fwrite fügt automatisch Zeilenenden hinzu.

  5. Muss ich die Datei schließen? Ein Dateistream wird beim Zerstören des Objekts geschlossen. Ein ausdrücklicher Aufruf von close() kann jedoch den Abschlusszeitpunkt verdeutlichen. Prüfen Sie danach den Streamstatus, wenn es auf den vollständigen Schreibvorgang ankommt. Bei einem C-FILE* rufen Sie fclose auf und prüfen dessen Rückgabewert.