Dieses Kapitel enthüllt, wie man Input/Output so aufbaut, dass der Code für Dateien, Speicher und sogar Prozesse einheitlich bleibt. Sie entdecken einen nicht offensichtlichen Ansatz: nicht mit “Dateien” zu arbeiten, sondern mit einer Geräte-Abstraktion — und dadurch die Entwicklung zu beschleunigen, die Zuverlässigkeit zu erhöhen und das Testen zu vereinfachen. Professionelle Entwickler verwenden diesen Stil, weil er einen klaren Vorher/Nachher-Kontrast bietet: weniger Bedingungen, mehr Wiederverwendung.
Darin — 3 Denkweisen für QIODevice (Lesen/Schreiben/Positionierung), praktische Techniken mit QDir + Filtern und sichereres Löschen über QFile::moveToTrash() in Qt6. Plus — eine fertige Architektur zur Änderungsüberwachung über QFileSystemWatcher, damit die Oberfläche asynchron und ohne Blockierungen aktualisiert wird.
Wenn diese Techniken jetzt nicht angewendet werden — wird die nächste “triviale” Dateiarbeit wieder einen Abend fressen.
Das Kapitel enthält Code-Beispiele, die sofort einsatzbereit sind.
Selbstüberprüfung zum Kapitel
Warum ist die Klasse QIODevice abstrakt und welche Methoden müssen bei der Erstellung eines eigenen Input/Output-Geräts implementiert werden?Antwort
Richtige Antwort: QIODevice ist abstrakt, um eine einheitliche Schnittstelle für alle Input/Output-Geräte zu gewährleisten. Bei Vererbung müssen readData() und writeData() implementiert werden, normalerweise auch open(), close() und atEnd().
Warum muss in der Klasse QDataStream die Methode setVersion() explizit vor dem Schreiben von Daten aufgerufen werden?Antwort
Richtige Antwort: Das QDataStream-Format hat sich zwischen Qt-Versionen geändert. Die explizite Versionangabe garantiert, dass Daten, die in einer Qt-Version geschrieben wurden, in einer anderen Version korrekt gelesen werden können.
Worin besteht der grundlegende Unterschied zwischen QTextStream und QDataStream, und wann verwendet man welchen?Antwort
Richtige Antwort: QTextStream ist für Textdaten in Unicode gedacht und konvertiert Zahlen in Text; QDataStream — für binäre Daten im plattformunabhängigen Format. Verwenden Sie QTextStream für Textdateien, QDataStream — für Objekt-Serialisierung und Netzwerkaustausch.
Warum sollte die Methode readAll() vorsichtig verwendet werden, und wie kann man den Speicherverbrauch bei ihrer Anwendung reduzieren?Antwort
Richtige Antwort: readAll() lädt die gesamte Datei in den Speicher, was bei großen Dateien Probleme verursachen kann. Der Speicherverbrauch kann reduziert werden, indem man qCompress() und qUncompress() auf QByteArray-Daten anwendet, wenn die Datei redundante Informationen enthält.
Warum wird im Beispiel zur rekursiven Dateisuche QApplication::processEvents() innerhalb der Methode start() aufgerufen?Antwort
Richtige Antwort: Die Dateisuche kann langwierig sein und wird im Hauptthread ausgeführt, was zum “Einfrieren” der GUI führt. processEvents() ermöglicht die Verarbeitung angesammelter Events und erhält die Reaktionsfähigkeit der Oberfläche.
Worin besteht der Vorteil der Verwendung von QFile::moveToTrash() in Qt6 gegenüber remove()?Antwort
Richtige Antwort: moveToTrash() verschiebt die Datei in den OS-Papierkorb und ermöglicht Wiederherstellung, während remove() die Datei unwiderruflich löscht.
Welchen praktischen Nutzen hat die Klasse QBuffer und in welchen Szenarien sollte sie angewendet werden?Antwort
Richtige Antwort: QBuffer emuliert eine Datei im RAM, was deutlich schneller als Disk-Operationen ist. Nützlich für Caching von Rasterbildern, temporäre Datenspeicherung und Testen von I/O-Code ohne Erstellung echter Dateien.
Warum sollte man QStandardPaths statt hartcodierter Strings zum Abrufen von Benutzerverzeichnissen verwenden?Antwort
Richtige Antwort: Pfade zu Standardverzeichnissen unterscheiden sich zwischen Plattformen und können sich ändern. QStandardPaths gewährleistet plattformunabhängigen und korrekten Zugriff auf Dokumente-, Einstellungs-, Cache- und andere Verzeichnisse.
Was passiert, wenn man QFile im Modus QIODevice::Truncate öffnet?Antwort
Richtige Antwort: Alle bestehenden Dateidaten werden beim Öffnen gelöscht, die Datei wird leer und bereit zum Schreiben neuer Daten vom Anfang an.
Wie benachrichtigt die Klasse QFileSystemWatcher über Änderungen, und warum blockiert dies nicht den Hauptthread?Antwort
Richtige Antwort: QFileSystemWatcher verwendet die Signale fileChanged() und directoryChanged() für asynchrone Benachrichtigungen. Die Überwachung erfolgt im Hintergrund ohne Blockierung des Hauptthreads der Anwendung.
Was passiert beim Versuch, die Methoden seek() und pos() für eine Netzwerkverbindung (QAbstractSocket) zu verwenden?Antwort
Richtige Antwort: Diese Methoden verlieren bei sequentiellem Zugriff (wie Netzwerkverbindung) ihren Sinn, da sie nur für direkten Zugriff anwendbar sind — QFile, QBuffer und QTemporaryFile.
Warum sollte man das Flag QDir::NoDotAndDotDot statt expliziter Prüfung auf “.” und “..” verwenden?Antwort
Richtige Antwort: Das Flag macht den Code sauberer, verständlicher und weniger fehleranfällig, indem es spezielle Verzeichnisse beim Aufruf von entryList() automatisch ausschließt.
Worin besteht der Vorteil der Verwendung von QTemporaryFile gegenüber selbstständiger Erstellung einer temporären Datei?Antwort
Richtige Antwort: QTemporaryFile generiert automatisch einen eindeutigen Namen (vermeidet Konflikte), platziert die Datei im korrekten temporären Verzeichnis und löscht die Datei automatisch bei Objektzerstörung.
Was passiert, wenn man bei der Arbeit mit QDataStream Daten mit Version Qt_6_9 schreibt, aber ohne Versionsangabe liest?Antwort
Richtige Antwort: Die Daten können fehlerhaft gelesen werden oder gar nicht gelesen werden, da QDataStream das Standardformat verwenden wird, das vom Schreibformat abweichen kann.
Praktische Aufgaben
Einfaches Niveau
Dateiinformations-Viewer
Erstellen Sie eine Qt-Anwendung mit einem Textfeld zur Eingabe eines Dateipfads und einem Button “Informationen anzeigen”. Bei Button-Klick soll die Anwendung anzeigen: Dateiname, Erweiterung, Größe in Bytes (und in lesbarem Format), Erstellungsdatum, Datum der letzten Änderung sowie Prüfung — ob die Datei ausführbar, versteckt, les- und schreibbar ist.
Hinweise: Verwenden Sie QFileInfo zum Abrufen aller Dateiinformationen. Die Methode exists() hilft beim Prüfen der Dateiexistenz. Zur Größenkonvertierung verwenden Sie eine Funktion aus dem Kapitel-Beispiel oder implementieren Sie Ihre eigene. Die Methoden created(), lastModified() geben QDateTime zurück, das über toString() in String konvertiert werden kann.
Mittleres Niveau
Texteditor mit Auto-Speicherung
Entwickeln Sie einen einfachen Texteditor mit QTextEdit, der den Inhalt automatisch alle 30 Sekunden in eine Datei speichert (verwenden Sie QTimer). Implementieren Sie ein Menü mit Punkten “Öffnen”, “Speichern unter”, “In Großbuchstaben exportieren”. Beim Öffnen einer Datei verwenden Sie QTextStream zum Lesen. Fügen Sie eine Statusleiste hinzu, die Zeit der letzten Speicherung und Größe des aktuellen Dokuments anzeigt.
Hinweise: QTimer mit Intervall 30000 ms für Auto-Speicherung. Verwenden Sie QTextStream zum Lesen/Schreiben von Textdateien. QFileDialog::getOpenFileName() und getSaveFileName() für Dialoge. Die Methode toPlainText() von QTextEdit gibt den gesamten Text. QString::toUpper() für Konvertierung. QStatusBar zur Statusanzeige.
Schwieriges Niveau
Backup-Manager mit Überwachung
Erstellen Sie eine Anwendung zum Backup eines gewählten Verzeichnisses. Verwenden Sie QFileSystemWatcher zur Überwachung von Änderungen im Quellverzeichnis. Bei Erkennung von Änderungen kopieren Sie automatisch geänderte Dateien ins Backup-Verzeichnis. Implementieren Sie Dateifilterung nach Maske (z.B. nur *.cpp und *.h). Fügen Sie die Möglichkeit zur Kompression von Backups über qCompress() und Speicherung in QDataStream hinzu. Zeigen Sie ein Operationsprotokoll in QTextEdit mit Zeitstempeln an. Sehen Sie Einstellungen vor: Auswahl von Quell- und Zielverzeichnis, Aktivierung/Deaktivierung automatischen Kopierens, Dateimaske.
Hinweise: Verwenden Sie QFileSystemWatcher::addPath() zur Überwachung. Signal fileChanged() zum Tracking von Änderungen. QDir::entryList() mit Filtern zur Dateiauswahl nach Maske. QFile::copy() zum Kopieren oder Kombination read()/write() für komprimierte Kopien. QDataStream mit qCompress()/qUncompress() zur Kompression. QDateTime::currentDateTime().toString() für Zeitstempel. QSettings zum Speichern von Einstellungen zwischen Starts.
💬 Beteiligen Sie sich an der Diskussion!
Haben Sie die QIODevice-Hierarchie und Unterschiede zwischen Streams gemeistert? Haben Sie Fragen dazu, wann QTextStream und wann QDataStream zu verwenden ist?
Teilen Sie Ihre Erfahrungen mit Datei- und Verzeichnisarbeit in Qt, berichten Sie über unkonventionelle Lösungen oder stellen Sie Fragen zum Kapitelmaterial. Vielleicht haben Sie interessante Anwendungsfälle von QFileSystemWatcher oder QBuffer?