Neben dem vorherigen Artikel werden wir weiterhin Byte -Stream -Operationen in Java lernen.
Dekorateur gepufferter Stream BufferedInput/Ausgangsstream
Der Dekorateur -Stream ist tatsächlich ein Datei -IO -Stream, der auf einem Designmuster "Dekoratormodus" basiert, und unser Pufferstrom ist nur einer davon. Schauen wir uns an.
Zuvor haben wir Dateilesen und Schreiben von Streams FileInputStream und FileOutputStream sowohl gelesen als auch von Scheiben Byte oder Byte verwendet, was sehr zeitaufwändig ist.
Unser Pufferstrom kann die Anzahl der Bytes einer bestimmten Kapazität von der Festplatte gleichzeitig in den Speicher vorlesen, und die nachfolgenden Lesevorgänge werden direkt aus dem Speicher gelesen, um die Effizienz zu verbessern. Schauen wir uns die spezifische Implementierung gepufferter Streams an:
Nehmen wir BufferedInputStream als Beispiel zuerst, und erwähnen Sie kurz die Kerneigenschaften:
BUF ist ein Byte -Array, das zum Pufferlesen verwendet wird. Sein Wert wird kontinuierlich gefüllt, wenn der Stream gelesen wird, und nachfolgende Lesevorgänge können direkt auf diesem gepufferten Array basieren.
Default_buffer_size Gibt die Größe des Standardpuffer an, dh die Array -Länge von BUF. MAX_BUFFER_SIZE gibt die Obergrenze des Puffers an.
Zählen Sie auf den letzten gültigen Byte -Index im gepufferten Array. POS verweist auf die nächste Byte -Indexposition, die gelesen werden soll.
Markpos und Marklimit werden verwendet, um Lesevorgänge zu wiederholen.
Schauen wir uns als nächstes mehrere Beispielkonstruktoren von BufferedInputStream an:
public buferedInputStream (InputStream in) {this (in, default_buffer_size);}; public buferedInputStream (InputStream in, int size) {super (in); if (size <= 0) {werfen neuer illegalArgumentException ("Puffergröße <= 0"); } buf = new Byte [Größe];}Insgesamt muss er erstere nur in einer Inputstream -Instanz passieren, die "dekoriert" ist, und einen Puffer mit Standardgröße verwenden. Letzteres kann explizit die Größe des Puffers angeben.
Darüber hinaus speichert Super (IN) diese InputStream -Instanz in das In -Attributfeld der übergeordneten Klasse filterInputStream, und alle tatsächlichen Abliesevorgänge werden von dieser InputStream -Instanz ausgegeben.
Werfen wir einen Blick auf die wichtigsten Lesevorgänge und wie der Puffer gefüllt ist.
public synchronisierte int read () löscht ioException {if (pos> = count) {fill (); if (pos> = count) return -1; } return getbufiFopen () [pos ++] & 0xff;}Ich glaube, jeder ist bereits mit dieser Methode vertraut. Es liest das nächste Byte aus dem Stream und gibt es zurück, aber die detaillierte Implementierung ist immer noch etwas anders.
Zählen zeigt auf die nächste Position des gültigen Byte -Index im gepufferten Array, und POS verweist auf die nächste Position des zu lesen. Theoretisch kann POS nicht größer als die Anzahl sein, höchstens gleich.
Wenn POS gleich zählt, bedeutet dies, dass alle gültigen Bytes im Pufferarray gelesen wurden. Zu diesem Zeitpunkt müssen die "nutzlosen" Daten im Puffer verworfen werden, und eine Stapel neuer Daten wird von der Festplatte neu geladen, um den Puffer zu füllen.
Tatsächlich ist die Füllmethode das, was sie tut. Es hat viel Code, daher werde ich Sie nicht dazu bringen, ihn zu analysieren. Wenn Sie seine Funktion verstehen, ist es wahrscheinlich einfach, seine Implementierung zu analysieren.
Wenn POS nach dem Aufrufen der Füllmethode immer noch der Anzahl entspricht, bedeutet dies, dass die InputStream -Instanz keine Daten aus dem Stream gelesen hat, dh im Dateistrom sind keine Daten zu lesen. Hierzu siehe Zeile 246 der FILL -Methode.
Wenn der Puffer erfolgreich gefüllt ist, wird unsere Lesemethode im Allgemeinen ein Byte direkt aus dem Puffer entnommen und an den Anrufer zurückgibt.
Public synchronisierte int read (byte b [], int off, int len) {// .....}Diese Methode ist auch eine "Bekanntschaft", die keine unnötige Erklärung mehr hat, die Implementierung ist ähnlich.
Die Skip -Methode wird verwendet, um die Anzahl der Bytes einer bestimmten Länge für das fortgesetzte Lesen des Dateistroms zu überspringen:
public synchronisierte long übersprungen (lang n) {// ......}Eine Sache zu beachten ist, dass die Skip -Methode versucht, B -Bytes zu überspringen, aber es wird nicht garantiert, dass sie B -Bytes überspringt. Die Methode gibt die tatsächliche Anzahl der übersprungenen Bytes zurück. Wenn die verbleibende Anzahl verfügbarer Bytes im gepufferten Array weniger als N beträgt, wird die tatsächliche Anzahl der Bytes, die im gepufferten Array übersprungen werden können, schließlich übersprungen.
Lassen Sie uns schließlich über diese enge Methode sprechen:
public void close () löst ioException {byte [] buffer aus; while ((buffer = buf)! in = null; if (input! = null) input.close (); zurückkehren; } // sonst wiederholen, falls ein neuer BUF in fill ()}} verkauft wurdeDie schließende Methode entleert den "dekorierten" Stream und ruft seine enge Methode auf, um relevante Ressourcen freizugeben, wodurch der vom Pufferarray besetzte Speicherraum letztendlich gelöscht wird.
BufferedInputStream bietet Lesepufferfunktionen, während BufferedOutputStream Schreibpufferfunktionen bietet, dh die Speicherschreibvorgänge werden nicht sofort auf die Festplatte aktualisiert und vorübergehend im Puffer gespeichert und werden zusammen geschrieben, wenn der Puffer voll ist.
geschützte Byte Buf []; geschützte Int Count;
BUF repräsentiert den internen Puffer und die Anzahl der tatsächlichen Datenkapazität im Puffer, dh die Anzahl der effektiven Bytes in BUF und nicht die Länge des BUF -Arrays.
public bufferedOutputStream (outputStream) {this (out, 8192);} public bufferedOutputStream (outputStream, int Größe) {Super (out); if (size <= 0) {werfen neuer illegalArgumentException ("Puffergröße <= 0"); } buf = new Byte [Größe];}Bei derselben Implementierungsidee ist es erforderlich, eine Ausgangsstream -Stream -Instanz bereitzustellen, und kann auch die Puffergröße selektiv angeben.
public synchronisierte void write (int b) löst ioException {if (count> = buf.length) {flushBuffer (); } buf [count ++] = (byte) b;}Die Schreibmethode prüft zunächst, ob der Puffer diesen Schreibvorgang noch gut berücksichtigen kann. Wenn ein Schreibvorgang nicht eingeleitet werden kann, werden alle Pufferdaten in die Datenträgerdatei geschrieben, andernfalls wird der Puffer zuerst in den Puffer geschrieben.
Natürlich bietet BufferedOutputStream auch eine Flush -Methode, um eine Schnittstelle nach außen bereitzustellen. Sie müssen nicht warten, bis der Puffer voll ist, bevor der Puffer auf die Festplatte geschrieben wird. Sie können diese Methode auch explizit aufrufen, um den Puffer zu löschen und die Datenträgerdateien zu aktualisieren.
public synchronisierte void flush () löst ioException {flushbuffer () aus; out.flush ();}In Bezug auf gepufferte Streams wird der Kerninhalt wie oben eingeführt. Dies ist ein Strom, der die Effizienz erheblich verbessern kann. Durch die Anzahl der Festplattenzugriffe kann reduziert und die Effizienz der Programmausführung verbessert werden.
Wir werden nicht das Objekt -Serialisierungsstrom -ObjektInput/OutputStream und den Decorator Stream DataNput/OutputStream basierend auf Basistypen diskutieren. Wenn wir die Serialisierung lernen, werden wir diese beiden Byte -Streams erneut diskutieren.
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.