Vorwort
Im vorherigen Artikel haben wir den Dateityp abstrakter Festplattendateien eingeführt. Es wird nur verwendet, um eine Festplattendatei oder ein Verzeichnis abstrakt zu beschreiben, kann jedoch nicht auf den Inhalt einer Datei zugreifen und sie ändern.
Java IO Stream ist ein Design, das zum Lesen und Schreiben von Dateiinhalten verwendet wird. Es kann die Datenübertragung von Ausgangsdateidateiinhalt in Speicher- oder Ausgabespeicherdaten in Festplattendateien vervollständigen.
Das Design von Java IO -Streams ist nicht perfekt. Es hat eine große Anzahl von Klassen entworfen, was unser Verständnis von IO -Streams erhöht hat, aber es gibt nur zwei Hauptkategorien: Einer sind Byte -Streams für binäre Dateien, und der andere sind Zeichenströme für Textdateien. In diesem Artikel lernen wir zunächst die Prinzipien und Nutzungsszenarien verwandter Arten von Byte -Streams. Die spezifischen Stream -Typen sind hauptsächlich wie folgt:
Basisklassen -Byte -Stream -Eingang/Ausgangsstream
InputStream und OutputStream sind die Basisklassen zum Lesen von Byte -Streams bzw. das Schreiben von Byte -Streams. Alle Byte-bezogenen Ströme müssen von ihnen erben. Als abstrakte Klasse definieren sie auch die grundlegendsten Lese- und Schreibvorgänge. Schauen wir uns an:
Nehmen Sie InputStream als Beispiel:
public abstract int read () wirft ioException aus;
Dies ist eine abstrakte Methode und liefert keine Standardimplementierung, wobei die Unterklassen implementiert werden müssen. Der Zweck dieser Methode besteht darin, das nächste Byte der aktuellen Datei für Sie zurückzugeben.
Natürlich werden Sie auch feststellen, dass der Rückgabewert dieser Methode mit dem Ganzzahltyp "int" empfangen wird. Warum also nicht "Byte" verwenden?
Zunächst muss der von der Lesemethode zurückgegebene Wert eine acht-Bit-Binärin sein, und das Wertintervall, das von einer acht-Bit-Binärdatei eingenommen werden kann, lautet: "0000 0000, 1111 1111", dh der Bereich [-128, 127].
Die Lesemethode gibt auch an, dass die Datei, wenn die Datei bis zum Ende gelesen wird, kein nächstes Byte für das Lesen hat, der Wert -1 zurückgegeben wird. Wenn Byte als Rückgabewerttyp verwendet wird, sollten wir dann feststellen, ob dies der Dateninhalt in der Datei oder am Ende des Streams ist, wenn die Methode ein -1 zurückgibt?
Der INT -Typ nimmt vier Bytes ein, und die drei Bytes im hohen Bit sind alle 0. Wir verwenden nur das niedrigste Bit -Byte. Bei der Begegnung mit dem Ende des Stream -Flags gibt es -1 (32 1s) zurück, die durch vier Bytes dargestellt werden, was sich natürlich vom Wert -1 (24 0 + 8 1s) unterscheidet, der die Daten darstellt.
Als nächstes kommt auch eine Lesemethode, aber InputStream bietet eine Standardimplementierung:
public int read (byte b []) löst ioException (return read (b, 0, b.Length);} public int read (byte b [], int off, int len) aus.
Diese beiden Methoden sind im Wesentlichen gleich. Die erste Methode ist eine spezielle Form der zweiten Methode, mit der ein Array von Bytes übergeben werden kann und das Programm erfordert, dass die in der Datei ab dem Array -Indexposition 0 gelesenen Bytes die Anzahl der Bytes in der Länge des Arrays füllen.
Die zweite Methode ist etwas breiter, sodass Sie die Startposition und die Gesamtzahl der Bytes angeben können.
In InputStream gibt es mehrere andere Methoden, die im Grunde genommen nicht im Detail implementiert werden. Schauen wir es uns kurz an.
Die Mark -Methode markiert ein Flag an der aktuellen Stream -Leseposition, und die Reset -Methode setzt den Lesezeiger auf das Flag zurück.
Tatsächlich ist es unmöglich, das Lesen für das Lesen von Dateien zurückzusetzen, aber im Allgemeinen werden alle Bytes zwischen der Flag -Position und dem Reset -Punkt vorübergehend gespeichert. Wenn die Reset -Methode aufgerufen wird, wird sie tatsächlich wiederholt von der gespeicherten temporären Byte -Set wiederholt, sodass ReadLimit verwendet wird, um die maximale Cache -Kapazität zu begrenzen.
Die markernupportierte Methode wird verwendet, um festzustellen, ob der aktuelle Stream diesen "Fallback" -Lesoperation unterstützt.
OutputStream und InputStream sind ähnlich, außer dass einer geschrieben und der andere gelesen wird. Wir werden es hier nicht wiederholen.
Datei Byte Stream FileInput/OutputStream
Wir konzentrieren uns immer noch auf FileInputStream, und FileOutputStream ist ähnlich.
Erstens hat FileInputStream die folgenden Konstruktoren, um ein Objekt zu instanziieren:
public FileInputStream (String -Name) löst FileNotFoundException {this (name! = null? Neue Datei (Name): NULL);} aus public FileInputStream (Dateidatei) löscht FilenotFoundException {String name = (Datei! = null? Datei.getPath (): null); SecurityManager Security = System.getSecurityManager (); if (Sicherheit! = null) {Security.CheckRead (Name); } if (name == null) {throw New nullPoInterException (); } if (file.issinvalid ()) {neue FilenotFoundException ("Ungültiger Dateipfad"); } fd = new FileDescriptor (); fd.attach (dies); Pfad = Name; Öffnen (Name);}Diese beiden Konstruktoren sind im Wesentlichen gleich, erstere ist die besondere Form des letzteren. Schauen Sie sich die letztere Methode nicht an, von denen die meisten nur die Sicherheitsüberprüfung durchführen. Der Kern ist eine offene Methode, mit der eine Datei geöffnet wird.
Hauptsächlich diese beiden Konstruktoren, wenn die Datei nicht vorhanden ist oder der Dateipfad und der Name illegal sind, wird eine FilenotFoundException geworfen.
Denken Sie daran, dass es in der Basisklasseneingabestream eine abstrakte Methode gibt, bei der alle Unterklassen implementiert werden müssen, und FileInputStream wird mithilfe einer lokalen Methode implementiert:
public int read () löscht ioException {return read0 ();} Private native int read0 () löscht ioException aus;Wir haben keine Möglichkeit, die spezifische Implementierung von Read0 vorerst zu untersuchen, aber Sie müssen klar sein, dass die Funktion dieser Lesemethode verwendet wird, um das nächste Byte im Stream zurückzugeben und -1 zurückzugeben. Es bedeutet, dass es bis zum Ende der Datei gelesen wird und es keine Bytes zu lesen gibt.
Darüber hinaus gibt es in FileInputStream einige andere messbezogene Methoden, die meisten von ihnen werden jedoch mit lokalen Methoden implementiert. Schauen wir uns hier an:
Die internen Methoden von FileInputStream sind im Grunde genommen genau so, und es gibt einige fortgeschrittene und komplexe, die wir vorerst nicht verwenden können. Wir werden es später lernen. Schauen wir uns einen kurzen Blick auf ein Beispiel für das Lesen von Dateien an:
public static void main (String [] args) löst IOException {FileInputStream input = new FileInputStream ("C: //users//yanga//desktop//test.txt") aus; byte [] buffer = neues byte [1024]; int len = input.read (Puffer); String str = new String (Puffer); System.out.println (str); System.out.println (Len); input.close ();}Das Ausgangsergebnis ist sehr einfach. Es wird den Inhalt in unserer Testdatei und die tatsächliche Anzahl der vorgelesenen Bytes ausdrucken. Sorgfältige Schüler finden jedoch heraus, wie Sie sicherstellen können, dass der Inhalt in der Testdatei 1024 Bytes nicht überschreitet.
Um den Inhalt der Datei vollständig vorzulesen, besteht eine Lösung darin, den Puffer zu definieren, der groß genug ist, um alle Inhalte der Datei so weit wie möglich zu speichern.
Diese Methode ist offensichtlich unerwünscht, da es uns unmöglich ist, die tatsächliche Größe der zu lesen zu lesen. Es ist eine sehr schlechte Lösung, einfach ein übergroßes Byte -Array zu erstellen.
Der zweite Weg besteht darin, unseren dynamischen Byte -Array -Stream zu verwenden, der die Größe des internen Byte -Arrays dynamisch anpassen kann, um eine angemessene Kapazität zu gewährleisten, die wir später ausführlich einführen werden.
In Bezug auf FileOutputStream ist eine weitere Sache zu betonen, die der Konstruktor mit den folgenden zwei Konstruktoren hat:
public FileOutputStream (Zeichenfolge Name, Boolean Append) öffentlicher FileOutputStream (Dateidatei, boolean Append)
Der Parameteranhang gibt an, ob der Schreibbetrieb dieses Streams überschrieben oder angehängt wird. TRUE MECIONEN FALSE, FALSE MENSE OVERWERT.
BytearrayInput/OutputStream
Der sogenannte "Byte-Array-Stream" ist ein Stream, der um ein Byte-Array arbeitet. Es wird keine Streams wie andere Streams gelesen und geschrieben.
Obwohl der Byte-Array-Stream kein dateibasiertes Stream ist, ist er immer noch ein sehr wichtiger Stream, da das im Inneren eingekapselte Byte-Array nicht festgelegt, sondern dynamisch erweiterbar ist und häufig auf bestimmten Szenarien basiert, was sehr geeignet ist.
BytearrayInputStream ist ein Strom von Lese -Byte -Arrays, die durch den folgenden Konstruktor instanziiert werden können:
geschützte Byte buf []; geschützte int pos; geschützte int count; öffentliche bytearrayinputstream (Byte buf []) {this.buf = buf; this.pos = 0; this.count = buf.length;} public bytearrayinputstream (Byte buf [], int offset, int länge)BUF ist ein Byte -Array, das in BytearrayInputStream eingekapselt ist. Alle lesen Operationen von BytearrayInputStream drehen sich darum.
Daher wird bei der Instanziierung eines BytearrayinputStream -Objekts mindestens ein Ziel -Byte -Array übergeben.
Das POS -Attribut wird verwendet, um die Position des aktuellen Stream -Lesens aufzuzeichnen und die letztere Position des zuletzt gültigen Byte -Index des Ziel -Byte -Arrays zu zählen.
Nach dem Verständnis ist es nicht schwierig, verschiedene Möglichkeiten zu lesen, es zu lesen:
// Lesen Sie das nächste Byte public synchronisierte int read () {return (pos <count)? (BUF [POS ++] & 0xff): -1;} // Lesen Sie Len Bytes und geben Sie sie in Byte -Array B öffentlich synchronisiert int Read (Byte B [], int, int len) {// gleich, der Methodekörper ist länger, jeder prüft ihren eigenen jdk}}Darüber hinaus implementiert BytearrayInputStream auch die "Wiederholung" -Operation sehr einfach.
public void mark (int lesaHeadlimit) {mark = pos;} public synchronisierte void Reset () {pos = mark;}Da BytearrayInputStream auf Byte -Arrays basiert, sind alle wiederholten Lesevorgänge einfacher zu implementieren und reicht aus, um basierend auf Indizes zu implementieren.
BytearrayoutputStream ist ein Byte -Array -Stream, der geschrieben wurde. Viele Implementierungen haben immer noch ihre eigenen Merkmale. Schauen wir uns zusammen.
Zunächst sind diese beiden Eigenschaften erforderlich:
geschützte Byte BUF []; // Die Anzahl hier repräsentiert die Anzahl der gültigen Bytes in BUF -geschützter Int -Anzahl;
Konstruktor:
public bytearrayoutputStream () {this (32);} public bytearrayoutputStream (int Größe) {if (Größe <0) {Wirf neu illegalArgumentException ("Negative Anfangsgröße:"+ Größe); } buf = new Byte [Größe];}Die Kernaufgabe des Konstruktors besteht darin, das interne Byte -Array -BUF zu initialisieren, sodass Sie die Größe übergeben können, um die initialisierte Byte -Array -Größe explizit einzuschränken, andernfalls beträgt die Standardlänge 32.
Schreiben Sie Inhalte in BytearrayoutputStream von außen:
public synchronisierte void write (int b) {sealecapacity (count + 1); buf [count] = (byte) b; count + = 1;} public synchronisierte void write (byte b [], int off, int len) {if ((off <0) || (off> b.Length) || (len <0) || ((off + len) - b.Length> 0) {Wurf New IndexoutofBoundSexception (); } sealecapacity (count + len); System.ArrayCopy (b, aus, buf, count, len); zählen += len;}Angesichts der Tatsache, dass der erste Schritt aller Schreibvorgänge darin besteht, die Methode für die Sicherung aufzurufen, besteht der Zweck darin, sicherzustellen, dass das Byte -Array im aktuellen Stream diesen Schreibvorgang berücksichtigen kann.
Diese Methode ist auch sehr interessant. Wenn Sie feststellen, dass der interne BUF diesen Schreibvorgang nach der Berechnung nicht unterstützen kann, wird die Wachstumsmethode für die Expansion gefordert. Das Prinzip der Kapazitätserweiterung ähnelt dem von ArrayList, das auf die doppelte ursprüngliche Kapazität erweitert wird.
Darüber hinaus hat BytearrayoutputStream auch eine Schreibmethode:
public synchronisierte void writeTo (outputStream Out) löst IoException {out.write (buf, 0, count);} ausSchreiben Sie unser intern eingekapseltes Byte -Array in einen Ausgangsstrom.
Einige der verbleibenden Methoden werden ebenfalls sehr häufig verwendet:
Beachten Sie, dass diese beiden Streams zwar "Streams" genannt werden, sie jedoch nicht im Wesentlichen einige Ressourcen wie echte Streams zuweisen, sodass wir seine enge Methode nicht nennen müssen, und es ist nutzlos, es zu nennen (der Beamte hat keine Wirkung).
Die Testfälle werden nicht freigegeben. Ich werde alle in diesem Artikel verwendeten Codefälle später hochladen. Sie können sie selbst herunterladen.
Um die Länge zu steuern, wird das verbleibende Lernen im nächsten Artikel platziert.
Alle Codes, Bilder und Dateien im Artikel werden in der Cloud auf meinem GitHub gespeichert:
(https://github.com/singleyam/overview_java)
Sie können auch lokal herunterladen.
Zusammenfassen
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Referenzwert für das Studium oder die Arbeit eines jeden hat. Wenn Sie Fragen haben, können Sie eine Nachricht zur Kommunikation überlassen. Vielen Dank für Ihre Unterstützung bei Wulin.com.