EMZETT.
Login

Kurz: C++ liest und schreibt über Streams: std::cin/std::cout für die Konsole, std::ifstream/std::ofstream für Dateien, std::istringstream/std::ostringstream für Strings. Alle benutzen dieselben Operatoren << und >>.

Teil des Kurses C++

Kapitel 11 von 15 im Kurs C++. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

C++ liest und schreibt über Streams: std::cin/std::cout für die Konsole, std::ifstream/std::ofstream für Dateien, std::istringstream/std::ostringstream für Strings. Alle benutzen dieselben Operatoren << und >>.

#include <iostream>
#include <fstream>
#include <string>
#include <filesystem>
 
int main() {
    namespace fs = std::filesystem;
    const std::string pfad = "notiz.txt";
 
    {
        std::ofstream aus(pfad);                         // schreiben; Datei wird beim Blockende geschlossen (RAII)
        if (!aus) { std::cerr << "kann nicht schreiben\n"; return 1; }
        aus << "Zeile 1\n" << "Zeile " << 2 << '\n';
    }
    {
        std::ofstream anhang(pfad, std::ios::app);       // anhängen
        anhang << "Zeile 3\n";
    }
 
    std::ifstream ein(pfad);
    if (!ein) { std::cerr << "kann nicht lesen\n"; return 1; }
    std::string zeile;
    int nr = 0;
    while (std::getline(ein, zeile)) std::cout << ++nr << ": " << zeile << '\n';
 
    std::cout << fs::exists(pfad) << ' ' << fs::file_size(pfad) << " Bytes\n";
    fs::remove(pfad);
    std::ifstream fehlt("gibt-es-nicht.txt");
    std::cout << (fehlt.is_open() ? "offen" : "nicht gefunden") << '\n';
    return 0;
}

Ausgabe:

1: Zeile 1
2: Zeile 2
3: Zeile 3
1 24 Bytes
nicht gefunden

Dateien werden beim Zerstören des Streams automatisch geschlossen. Prüfe nach dem Öffnen mit if (!stream).

Ganze Datei einlesen

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
 
int main() {
    std::ofstream("daten.csv") << "name;alter\nMia;17\nTom;19\nZoe;21\n";
 
    std::ifstream f("daten.csv");
    std::stringstream puffer;
    puffer << f.rdbuf();                                 // alles auf einmal
    std::string inhalt = puffer.str();
    std::cout << inhalt.size() << " Zeichen\n";
 
    f.clear(); f.seekg(0);
    std::string kopf; std::getline(f, kopf);             // Kopfzeile überspringen
    int summe = 0;
    std::string zeile;
    while (std::getline(f, zeile)) {
        std::istringstream zeilenstrom(zeile);
        std::string name, alterText;
        std::getline(zeilenstrom, name, ';');            // bis zum Trennzeichen
        std::getline(zeilenstrom, alterText);
        summe += std::stoi(alterText);
    }
    std::cout << "Summe der Alter: " << summe << '\n';
    std::remove("daten.csv");
    return 0;
}

Ausgabe:

32 Zeichen
Summe der Alter: 57

Binärdaten

#include <iostream>
#include <fstream>
#include <vector>
 
int main() {
    std::vector<int> z{1, 2, 3, 4, 5};
    {
        std::ofstream aus("zahlen.bin", std::ios::binary);
        aus.write(reinterpret_cast<const char*>(z.data()), static_cast<std::streamsize>(z.size() * sizeof(int)));
    }
    std::vector<int> neu(5);
    std::ifstream ein("zahlen.bin", std::ios::binary);
    ein.read(reinterpret_cast<char*>(neu.data()), static_cast<std::streamsize>(neu.size() * sizeof(int)));
    std::cout << neu[0] << neu[4] << ' ' << ein.gcount() << " Bytes\n";
    std::remove("zahlen.bin");
    return 0;
}

Ausgabe:

15 20 Bytes

Formatieren der Ausgabe

#include <iostream>
#include <iomanip>
#include <format>
 
int main() {
    double pi = 3.14159265;
    std::cout << std::fixed << std::setprecision(2) << pi << '\n';
    std::cout << std::setw(8) << std::setfill('.') << 42 << '|' << std::left << std::setw(6) << 7 << "|\n";
    std::cout << std::hex << 255 << ' ' << std::dec << 255 << ' ' << std::scientific << 12345.678 << '\n';
    std::cout << std::format("{:>8.3f}|{:08b}|{:#x}\n", pi, 37, 255);
    return 0;
}

Ausgabe:

3.14
......42|7.....|
ff 255 1.23e+04
   3.142|00100101|0xff

Die Manipulatoren (std::setw, std::fixed …) wirken teils dauerhaft auf den Stream. std::format (C++20) ist handlicher und sicher.

std::filesystem

#include <iostream>
#include <filesystem>
#include <fstream>
#include <vector>
#include <algorithm>
 
namespace fs = std::filesystem;
 
int main() {
    fs::path wurzel = fs::temp_directory_path() / "kurs_demo";          // / setzt Pfade zusammen
    fs::create_directories(wurzel / "unter");
    std::ofstream(wurzel / "a.txt") << "eins";
    std::ofstream(wurzel / "unter" / "b.txt") << "zweiundzwanzig";
 
    std::vector<std::string> namen;
    for (const auto& eintrag : fs::recursive_directory_iterator(wurzel))
        if (eintrag.is_regular_file())
            namen.push_back(fs::relative(eintrag.path(), wurzel).generic_string() + " (" + std::to_string(eintrag.file_size()) + ")");
    std::sort(namen.begin(), namen.end());
    for (const auto& n : namen) std::cout << n << '\n';
 
    fs::path p = "/a/b/bild.png";
    std::cout << p.filename() << ' ' << p.extension() << ' ' << p.stem() << ' ' << p.parent_path() << '\n';
    fs::remove_all(wurzel);
    std::cout << fs::exists(wurzel) << '\n';
    return 0;
}

Ausgabe:

a.txt (4)
unter/b.txt (14)
"bild.png" ".png" "bild" "/a/b"
0

Merke

  • Streams: ifstream (lesen), ofstream (schreiben), stringstream (Strings), alle mit <</>>
  • RAII schließt Dateien automatisch; Öffnen mit if (!stream) prüfen
  • Zeilenweise: std::getline; Trennzeichen: std::getline(s, teil, ';')
  • Binär: std::ios::binary, write, read
  • Formatieren mit <iomanip> oder besser std::format
  • std::filesystem für Pfade, Ordner, Größen

Übungsaufgabe

Lies eine Textdatei zeilenweise, zähle Zeilen und Wörter und schreibe die Statistik in eine zweite Datei.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Fehlerbehandlung: Ausnahmen, optional und variant

Weiter: Nebenläufigkeit: Threads, Mutex und Futures

Alle Kapitel: C++ im Überblick