Java-Streams, Dateien und E/A

Streams, Dateien und IO (Eingabe/Ausgabe) in Java sind die Infrastruktur für das Lesen und Schreiben von Daten. Sie ermöglichen Programmen die Interaktion mit externen Daten (wie Dateien, Netzwerken, Systemeingabe usw.).

Das Paket java.io ist ein Kernpaket in der Java-Standardbibliothek und stellt Klassen für Systemeingabe und -ausgabe bereit. Es enthält Werkzeuge für die Verarbeitung von Datenströmen (Byte-Streams und Zeichenströme), Lesen und Schreiben von Dateien, Serialisierung und Datenformatierung.

java.io ist das grundlegende Paket für die Behandlung von Dateioperationen, Stream-Operationen und Low-Level-IO-Operationen.

Die Streams im Paket java.io unterstützen viele Formate, wie primitive Typen, Objekte, lokalisierte Zeichensätze und so weiter.

Ein Stream kann als eine Folge von Daten verstanden werden. Ein Eingabestream steht für das Lesen von Daten aus einer Quelle, und ein Ausgabestream steht für das Schreiben von Daten an ein Ziel.


Konsoleneingabe lesen

Die Java-Konsoleneingabe wird von System.in behandelt.

Um einen an die Konsole gebundenen Zeichenstrom zu erhalten, können Sie System.in in ein BufferedReader-Objekt einwickeln, um einen Zeichenstrom zu erstellen.

Das Folgende ist die grundlegende Syntax zum Erstellen eines BufferedReader:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

Nachdem das BufferedReader-Objekt erstellt wurde, können wir die read()-Methode verwenden, um ein Zeichen von der Konsole zu lesen, oder die readLine()-Methode, um eine Zeichenkette zu lesen.


Mehrere Zeichen aus der Konsoleneingabe lesen

Um ein Zeichen aus einem BufferedReader-Objekt zu lesen, verwenden Sie die read()-Methode. Ihre Syntax lautet wie folgt:

int read( ) throws IOException

Jedes Mal, wenn die read()-Methode aufgerufen wird, liest sie ein Zeichen aus dem Eingabestrom und gibt das Zeichen als Ganzzahlwert zurück. Sie gibt -1 zurück, wenn der Strom endet. Diese Methode wirft eine IOException.

Das folgende Programm demonstriert die Verwendung der read()-Methode, um kontinuierlich Zeichen von der Konsole zu lesen, bis der Benutzer eingibtq。

Code der Datei BRRead.java:

//Zeichen von der Konsole mit BufferedReader lesen import java.io.*; public class BRRead { public static void main(String[] args) throws IOException { char c; //Erstellen Sie einen BufferedReader mit System.in BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Zeichen eingeben, zum Beenden 'q' drücken."); //Zeichen lesen do { c = (char) br.read(); System.out.println(c); } while (c != 'q'); } }

Das Kompilierungs- und Ausführungsergebnis des obigen Beispiels ist wie folgt:

输入字符, 按下 'q' 键退出。
example
r
u
n
o
o
b


q
q

Strings aus der Konsoleneingabe lesen

Um einen String aus der Standardeingabe zu lesen, müssen Sie die Methode readLine() von BufferedReader verwenden.

Das allgemeine Format lautet:

String readLine( ) throws IOException

Das folgende Programm liest und zeigt Zeichenzeilen an, bis Sie das Wort "end" eingeben.

Code der Datei BRReadLines.java:

//Zeichen von der Konsole mit BufferedReader lesen import java.io.*; public class BRReadLines { public static void main(String[] args) throws IOException { //Erstellen Sie einen BufferedReader mit System.in BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str; System.out.println("Geben Sie Textzeilen ein."); System.out.println("Geben Sie 'end' ein, um zu beenden."); do { str = br.readLine(); System.out.println(str); } while (!str.equals("end")); } }

Das Kompilierungs- und Ausführungsergebnis des obigen Beispiels ist wie folgt:

Enter lines of text.
Enter 'end' to quit.
This is line one
This is line one
This is line two
This is line two
end
end

In Versionen nach JDK 5 können wir auch dieJava ScannerKlasse verwenden, um Konsoleneingabe zu erhalten.


Konsolenausgabe

Wie bereits erwähnt, erfolgt die Konsolenausgabe durch print() und println(). Diese Methoden sind alle in der Klasse PrintStream definiert, und System.out ist eine Referenz auf ein Objekt dieser Klasse.

PrintStream erbt von der Klasse OutputStream und implementiert die Methode write(). Somit kann write() auch verwendet werden, um in die Konsole zu schreiben.

Die einfachste von PrintStream definierte Form von write() lautet wie folgt:

void write(int byteval)

Diese Methode schreibt die niederwertigen acht Bits von byteval in den Stream.

Beispiel

Das folgende Beispiel verwendet write(), um das Zeichen "A" gefolgt von einem Zeilenumbruch auf dem Bildschirm auszugeben:

Code der Datei WriteDemo.java:

import java.io.*; //Demonstriert System.out.write(). public class WriteDemo { public static void main(String[] args) { int b; b = 'A'; System.out.write(b); System.out.write('\n'); } }

Beim Ausführen des obigen Beispiels wird das Zeichen "A" im Ausgabefenster ausgegeben.

A

Hinweis:Die Methode write() wird nicht häufig verwendet, weil die Methoden print() und println() bequemer zu verwenden sind.


Dateien lesen und schreiben

Wie bereits erwähnt, ist ein Stream als Datenfolge definiert. Eingabestreams werden verwendet, um Daten aus einer Quelle zu lesen, und Ausgabestreams werden verwendet, um Daten an ein Ziel zu schreiben.

Das folgende Diagramm ist ein Klassenhierarchiediagramm, das Eingabe- und Ausgabestreams beschreibt.

Byte-Streams (Verarbeitung binärer Daten)

Byte-Streams werden verwendet, um binäre Daten wie Dateien, Bilder, Videos usw. zu verarbeiten.

KlassennameTypeBeschreibung
InputStreamAbstrakte Klasse (Eingabestream)Die Oberklasse aller Byte-Eingabestreams, die Byte-Eingabeoperationen verarbeitet.
OutputStreamAbstrakte Klasse (Ausgabestream)Die Oberklasse aller Byte-Ausgabestreams, die Byte-Ausgabeoperationen verarbeitet.
FileInputStreamEingabestreamLiest Byte-Daten aus einer Datei.
FileOutputStreamAusgabestreamSchreibt Byte-Daten in eine Datei.
BufferedInputStreamEingabestreamBietet Pufferung für Byte-Eingabestreams, um die Leseeffizienz zu verbessern.
BufferedOutputStreamAusgabestreamBietet Pufferung für Byte-Ausgabestreams, um die Schreibeffizienz zu verbessern.
ByteArrayInputStreamEingabestreamVerwendet ein Byte-Array im Speicher als Eingabequelle.
ByteArrayOutputStreamAusgabestreamSchreibt Daten in ein Byte-Array im Speicher.
DataInputStreamEingabestreamErmöglicht das Lesen primitiver Java-Datentypen aus einem Eingabestream (wie z. B.int、float、boolean)。
DataOutputStreamAusgabestreamErmöglicht das Schreiben primitiver Java-Datentypen in einen Ausgabestream.
ObjectInputStreamEingabestreamLiest serialisierte Objekte aus einem Eingabestream.
ObjectOutputStreamAusgabestreamSerialisiert Objekte und schreibt sie in einen Ausgabestream.
PipedInputStreamEingabestreamWird verwendet, um Byte-Daten in einer Pipe zu lesen, normalerweise mitPipedOutputStreamWird zusammen verwendet.
PipedOutputStreamAusgabestreamWird verwendet, um Byte-Daten in einer Pipe zu schreiben, normalerweise mitPipedInputStreamWird zusammen verwendet.
FilterInputStreamEingabestreamEine Wrapper-Klasse für Byte-Eingabestreams, die zum Filtern anderer Eingabestreams verwendet wird.
FilterOutputStreamAusgabestreamEine Wrapper-Klasse für Byte-Ausgabestreams, die zum Filtern anderer Ausgabestreams verwendet wird.
SequenceInputStreamEingabestreamKombiniert mehrere Eingabestreams zu einem Eingabestream zur Verarbeitung.

Zeichenströme (Verarbeitung von Textdaten)

Zeichenströme werden verwendet, um Textdaten zu verarbeiten, z. B. zum Lesen und Schreiben von Zeichenfolgen oder Dateien.

KlassennameTypeBeschreibung
ReaderAbstrakte Klasse (Eingabestream)Die Oberklasse aller Zeichen-Eingabestreams, die Zeicheneingabeoperationen verarbeitet.
WriterAbstrakte Klasse (Ausgabestream)Die Oberklasse aller Zeichenausgabeströme, die Zeichenausgabeoperationen verarbeitet.
FileReaderEingabestreamLiest Zeichendaten aus einer Datei.
FileWriterAusgabestreamSchreibt Zeichendaten in eine Datei.
BufferedReaderEingabestreamBietet Pufferung für Zeicheneingabeströme, unterstützt zeilenweises Lesen und verbessert die Leseeffizienz.
BufferedWriterAusgabestreamBietet Pufferung für Zeichenausgabeströme, unterstützt zeilenweises Schreiben und verbessert die Schreibeffizienz.
CharArrayReaderEingabestreamVerwendet ein Zeichenarray als Eingabequelle.
CharArrayWriterAusgabestreamSchreibt Daten in ein Zeichenarray.
StringReaderEingabestreamVerwendet eine Zeichenkette als Eingabequelle.
StringWriterAusgabestreamSchreibt Daten in einen Zeichenkettenpuffer.
PrintWriterAusgabestreamKomfortabler Zeichenausgabestrom, unterstützt Auto-Flush und formatierte Ausgabe.
PipedReaderEingabestreamWird verwendet, um Zeichendaten in einer Pipe zu lesen, normalerweise mitPipedWriterzusammen verwendet.
PipedWriterAusgabestreamWird verwendet, um Zeichendaten in eine Pipe zu schreiben, normalerweise mitPipedReaderzusammen verwendet.
LineNumberReaderEingabestreamGepufferter Zeichen-Eingabestream mit Zeilennummern, der das Verfolgen der gerade gelesenen Zeilennummer ermöglicht.
PushbackReaderEingabestreamErmöglicht das Zurückschieben von Zeichen in den Stream nach dem Lesen, sodass sie erneut gelesen werden können.

Hilfsklassen (weitere wichtige Klassen)

Hilfsklassen bieten Unterstützung für Dateien, Verzeichnisse und wahlfreien Dateizugriff.

KlassennameTypeBeschreibung
FileDatei- und VerzeichnisoperationenWird verwendet, um eine Datei oder ein Verzeichnis darzustellen, und bietet Dateioperationen wie Erstellen, Löschen, Umbenennen usw.
RandomAccessFileDatei mit wahlfreiem ZugriffUnterstützt wahlfreien Zugriff auf Dateien, sodass Daten an jeder beliebigen Position in der Datei gelesen und geschrieben werden können.
ConsoleKonsolen-Eingabe/AusgabeBietet Eingabe- und Ausgabeunterstützung für die Systemkonsole.

Die beiden wichtigen Streams, die als Nächstes besprochen werden, sindFileInputStreamundFileOutputStream。


FileInputStream

Dieser Stream wird verwendet, um Daten aus einer Datei zu lesen. Sein Objekt kann mit dem Schlüsselwort new erstellt werden.

Es gibt mehrere Konstruktoren, die zum Erstellen von Objekten verwendet werden können.

Sie können einen Dateinamen vom Typ String verwenden, um ein Eingabestreamobjekt zum Lesen einer Datei zu erstellen:

InputStream f = new FileInputStream("C:/java/hello");

Sie können auch ein Dateiobjekt verwenden, um ein Eingabestreamobjekt zum Lesen einer Datei zu erstellen. Zuerst müssen wir die Methode File() verwenden, um ein Dateiobjekt zu erstellen:

File f = new File("C:/java/hello"); InputStream in = new FileInputStream(f);

Sobald das InputStream-Objekt erstellt wurde, können Sie die folgenden Methoden verwenden, um den Stream zu lesen oder andere Stream-Operationen auszuführen.

MethodeBeschreibungBeispielcode
int read()Liest ein Byte Daten, wobei der Rückgabewert eine Ganzzahl zwischen 0 und 255 ist. Gibt -1 zurück, wenn das Ende des Streams erreicht ist.int data = inputStream.read();
int read(byte[] b)Liest Bytes aus dem Eingabestream und speichert sie im Byte-Arraybund gibt die tatsächliche Anzahl der gelesenen Bytes zurück. Gibt -1 zurück, wenn das Ende des Streams erreicht ist.byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer);
int read(byte[] b, int off, int len)Liest bis zulenBytes aus dem Eingabestream und speichert sie im Byte-Arraybvonoffbeginnend an der Offset-Position, wobei die tatsächliche Anzahl der gelesenen Bytes zurückgegeben wird. Gibt -1 zurück, wenn das Ende des Streams erreicht ist.byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer, 0, buffer.length);
long skip(long n)Überspringt und verwirftnBytes im Eingabestream und gibt die tatsächliche Anzahl der übersprungenen Bytes zurück.long skippedBytes = inputStream.skip(100);
int available()Gibt die Anzahl der Bytes zurück, die gelesen werden können (ohne zu blockieren).int availableBytes = inputStream.available();
void close()Schließt den Eingabestream und gibt alle mit diesem Stream verbundenen Ressourcen frei.inputStream.close();
void mark(int readlimit)Setzt eine Markierung an der aktuellen Position im Stream,readlimitist die Obergrenze für die Anzahl der Bytes, die gelesen werden können.inputStream.mark(1024);
void reset()Setzt den Stream an die Position der letzten Markierung zurück. Wenn keine Markierung vorhanden oder die Markierung ungültig ist, wird eine Ausnahme ausgelöstIOException。inputStream.reset();
boolean markSupported()Prüft, ob der aktuelle Eingabestream unterstütztmark()undreset()Operation.boolean isMarkSupported = inputStream.markSupported();

Zusätzlich zu InputStream gibt es einige andere Eingabestreams. Weitere Details finden Sie unter dem folgenden Link:


FileOutputStream

Diese Klasse wird verwendet, um eine Datei zu erstellen und Daten in die Datei zu schreiben.

Wenn die Zieldatei nicht existiert, bevor der Stream die Datei für die Ausgabe öffnet, erstellt der Stream die Datei.

Es gibt zwei Konstruktoren, die verwendet werden können, um ein FileOutputStream-Objekt zu erstellen.

Verwenden Sie einen Dateinamen vom Typ String, um ein Ausgabestrom-Objekt zu erstellen:

OutputStream f = new FileOutputStream("C:/java/hello")

Sie können auch ein Dateiobjekt verwenden, um einen Ausgabestrom zu erstellen, um in eine Datei zu schreiben. Zuerst müssen wir die Methode File() verwenden, um ein Dateiobjekt zu erstellen:

File f = new File("C:/java/hello"); OutputStream fOut = new FileOutputStream(f);

Nachdem Sie das OutputStream-Objekt erstellt haben, können Sie die folgenden Methoden verwenden, um in den Stream zu schreiben oder andere Stream-Operationen auszuführen.

MethodeBeschreibungBeispielcode
void write(int b)Schreibt das angegebene Byte in den Ausgabestrom; die niedrigstwertigen 8 Bits vonbwird in den Stream geschrieben.outputStream.write(255);
void write(byte[] b)Schreibt alle Bytes im Byte-Arraybin den Ausgabestream.byte[] data = "Hello".getBytes(); outputStream.write(data);
void write(byte[] b, int off, int len)Schreibt Bytes aus dem Byte-Arraybbeginnend beim Offsetoffbeginnend beilenBytes in den Ausgabestream.byte[] data = "Hello".getBytes(); outputStream.write(data, 0, data.length);
void flush()Leert den Ausgabestream und erzwingt, dass alle gepufferten Daten geschrieben werden, wodurch sichergestellt wird, dass die Daten sofort in die Zielausgabe geschrieben werden.outputStream.flush();
void close()Schließt den Ausgabestream und gibt alle mit diesem Stream verbundenen Ressourcen frei. Nach dem Schließen können keine Schreibvorgänge mehr ausgeführt werden.outputStream.close();

Neben OutputStream gibt es noch einige andere Ausgabestreams. Weitere Details finden Sie unter dem folgenden Link:

Beispiel

Das folgende Beispiel demonstriert die Verwendung von InputStream und OutputStream:

fileStreamTest.java Datei-Code:

import java.io.*; public class fileStreamTest { public static void main(String[] args) { try { byte bWrite[] = { 11, 21, 3, 40, 5 }; OutputStream os = new FileOutputStream("test.txt"); for (int x = 0; x < bWrite.length; x++) { os.write(bWrite[x]); // schreibt die Bytes } os.close(); InputStream is = new FileInputStream("test.txt"); int size = is.available(); for (int i = 0; i < size; i++) { System.out.print((char) is.read() + " "); } is.close(); } catch (IOException e) { System.out.print("Exception"); } } }

Das obige Programm erstellt zunächst die Datei test.txt, schreibt die angegebenen Zahlen in binärer Form in die Datei und gibt sie gleichzeitig auf der Konsole aus.

Da der obige Code binäres Schreiben verwendet, können verstümmelte Zeichen auftreten. Sie können das folgende Codebeispiel verwenden, um das Problem mit den verstümmelten Zeichen zu lösen:

Code der Datei fileStreamTest2.java:

//Dateiname: fileStreamTest2.java import java.io.*; public class fileStreamTest2 { public static void main(String[] args) throws IOException { File f = new File("a.txt"); FileOutputStream fop = new FileOutputStream(f); //Erstellt ein FileOutputStream-Objekt. Wenn die Datei nicht existiert, wird sie automatisch erstellt. OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8"); //Erstellt ein OutputStreamWriter-Objekt. Der Parameter kann die Kodierung angeben; standardmäßig wird die Standardkodierung des Betriebssystems verwendet, unter Windows ist dies gbk. writer.append("chinesische Eingabe"); //In den Puffer schreiben writer.append("\r\n"); //Newline writer.append("English"); //Leere den Puffer und schreibe in die Datei. Wenn unten kein weiterer Inhalt mehr zu schreiben ist, schreibt ein direkter Aufruf von close ebenfalls. writer.close(); //Schließe den Schreibstream; gleichzeitig wird der Inhalt des Puffers in die Datei geschrieben, daher ist das Obige auskommentiert. fop.close(); //Schließe den Ausgabestream und gib Systemressourcen frei. FileInputStream fip = new FileInputStream(f); //Erzeuge ein FileInputStream-Objekt. InputStreamReader reader = new InputStreamReader(fip, "UTF-8"); //Erzeuge ein InputStreamReader-Objekt; die Kodierung ist dieselbe wie beim Schreiben. StringBuffer sb = new StringBuffer(); while (reader.ready()) { sb.append((char) reader.read()); //Wandle in char um und hänge es an das StringBuffer-Objekt an. } System.out.println(sb.toString()); reader.close(); //Den Lese-Stream schließen. fip.close(); //Den Eingabestrom schließen und Systemressourcen freigeben. } }

Dateien und I/O

Es gibt auch einige Klassen im Zusammenhang mit Dateien und I/O, die wir kennen müssen:


Verzeichnisse in Java

Verzeichnisse erstellen:

Es gibt zwei Methoden in der File-Klasse, mit denen Ordner erstellt werden können:

  • mkdir( )Die Methode erstellt einen Ordner. Sie gibt bei Erfolg true und bei Fehler false zurück. Ein Fehler bedeutet, dass der vom File-Objekt angegebene Pfad bereits existiert oder dass der Ordner nicht erstellt werden kann, weil der gesamte Pfad noch nicht existiert.
  • mkdirs()Die Methode erstellt einen Ordner und alle seine übergeordneten Ordner.

Das folgende Beispiel erstellt den Ordner "/tmp/user/java/bin":

Code der Datei CreateDir.java:

import java.io.File; public class CreateDir { public static void main(String[] args) { String dirname = "/tmp/user/java/bin"; File d = new File(dirname); //Jetzt wird das Verzeichnis erstellt d.mkdirs(); } }

Kompilieren und führen Sie den obigen Code aus, um das Verzeichnis "/tmp/user/java/bin" zu erstellen.

Hinweis:Java unterscheidet Dateipfadtrennzeichen unter UNIX und Windows automatisch je nach Konvention. Wenn Sie das Trennzeichen (/) in einer Windows-Version von Java verwenden, kann der Pfad trotzdem korrekt aufgelöst werden.


Verzeichnisse lesen

Ein Verzeichnis ist eigentlich ein File-Objekt, das andere Dateien und Ordner enthält.

Wenn Sie ein File-Objekt erstellen und es ein Verzeichnis ist, gibt der Aufruf der Methode isDirectory() true zurück.

Sie können die Liste der darin enthaltenen Dateien und Ordner extrahieren, indem Sie die Methode list() für dieses Objekt aufrufen.

Das folgende Beispiel zeigt, wie Sie die Methode list() verwenden, um den Inhalt eines Ordners zu überprüfen:

Code der Datei DirList.java:

import java.io.File; public class DirList { public static void main(String args[]) { String dirname = "/tmp"; File f1 = new File(dirname); if (f1.isDirectory()) { System.out.println("Verzeichnis" + dirname); String s[] = f1.list(); for (int i = 0; i < s.length; i++) { File f = new File(dirname + "/" + s[i]); if (f.isDirectory()) { System.out.println(s[i] + "ist ein Verzeichnis"); } else { System.out.println(s[i] + "ist eine Datei"); } } } else { System.out.println(dirname + "ist kein Verzeichnis"); } } }

Das Ergebnis des Kompilierens und Ausführens des obigen Beispiels ist wie folgt:

目录 /tmp
bin 是一个目录
lib 是一个目录
demo 是一个目录
test.txt 是一个文件
README 是一个文件
index.html 是一个文件
include 是一个目录

Löschen von Verzeichnissen oder Dateien

Um eine Datei zu löschen, können Sie diejava.io.File.delete()Methode verwenden.

Der folgende Code löscht das Verzeichnis/tmp/java/. Beachten Sie, dass Sie beim Löschen eines Verzeichnisses sicherstellen müssen, dass sich keine anderen Dateien in diesem Verzeichnis befinden, damit es korrekt gelöscht werden kann; andernfalls schlägt das Löschen fehl.

Struktur des Testverzeichnisses:

/tmp/java/
|-- 1.log
|-- test

Code der Datei DeleteFileDemo.java:

import java.io.File; public class DeleteFileDemo { public static void main(String[] args) { //Ändern Sie dies in Ihr eigenes Testverzeichnis File folder = new File("/tmp/java/"); deleteFolder(folder); } //Dateien und Verzeichnisse löschen public static void deleteFolder(File folder) { File[] files = folder.listFiles(); if (files != null) { for (File f : files) { if (f.isDirectory()) { deleteFolder(f); } else { f.delete(); } } } folder.Löschen(); } }
Weitere Erweiterungen