1. 程式人生 > >21 Java學習之位元組流(InputStream和OutPutStream)

21 Java學習之位元組流(InputStream和OutPutStream)

 

一.流的分類

 

1、從功能上:輸入流、輸出流

2、從結構上:位元組流、字元流

3、從來源上:節點流、過濾流

  其中InputStream/OutputStream是為位元組流而設計的,Reader/Writer是為字元流而設計的。處理位元組或者二進位制物件使用位元組流,處理字元或者字串使用字元流。

        在最底層,所有的輸入/輸出都是位元組形式的,基於字元的流只在處理字元的時候提供方便有效的方法。

  節點流是從特定的地方讀寫的流,例如磁碟或者記憶體空間,也就是這種流是直接對接目標的。

  過濾流是使用節點流作為輸入輸出的,就是在節點流的基礎上進行包裝,新增一些特定的功能。

二. 什麼是輸入流和輸出流?

        輸入和輸出流的概念其實都是針對記憶體(note:或者直接理解為我們的程式)說的。比如:我們常用來列印到控制檯的命令System.out.println()它就是out,對於記憶體來說,把字串列印到螢幕上就是從記憶體流向了螢幕的控制檯;而等待使用者輸入命令確實System.in就是從鍵盤將字元輸入到記憶體中。

因此:  從記憶體出:out (輸出流)             進入到記憶體:in(輸入流)

note:因為從記憶體到螢幕,就是寫檔案的流向;從硬碟到記憶體就是讀檔案的流向。

       如果時網路訪問中,我們請求訪問網頁就是in,因為我們訪問頁面的時候時需要抓取該頁面的一個html檔案,因此是從網路到記憶體的流向;倘若有一個登陸頁面,那麼就是從記憶體到伺服器了,因為需要從記憶體寫資料到登陸介面,即out.

 三. InputStream

       其中有底色標註的為節點流,無底色標註的為過濾流,其中FilterInputStream在JDK中的定義為:包含其他一些輸入流,它將這些流用作其基本資料來源,可以直接傳輸資料或提供一些額外的功能,這個類本身並不經常被我們使用,常用的是它的子類。(note:上面InputStream的實現類沒有例完,只是常用的)

定義了位元組輸入模式的抽象類,該類提供了三個過載的read方法:

我們可以看到,三個read方法中,其中有一個是抽象的。那在這裡思考這樣一個問題:為什麼只有第一個是抽象的, 其他兩個是具體的?

因為後面兩個方法內部最終會去呼叫第一個方法,所以在InputStream派生類中只需要重寫第一個方法就可以了。在這裡可以看到第一個read方法是與具體的I/O裝置相關的,需要子類去實現。

 1. 常用的位元組輸入流

  • InputStream  
  • FileInputStream
  • BufferedInputStream (BufferedInputStream不是InputStream的直接實現子類,是FilterInputStream的子類)

它們的區別與用途:

(1)InputStream:是抽象基類。其中定義了幾個特別常用的方法,比如read和close方法。

(2)FileInputStream:主要用來操作檔案的輸入流。

(3)BufferedInputStream:一般讀取是從硬盤裡面讀取資料;而帶有緩衝區之後,BufferedInputStream是提前將資料封裝到了記憶體中,因此記憶體中操作資料會更快,從而擁有比非緩衝區更高的效率。

2. 對寫資料的邏輯順序

(1)open a stream

(2)while more information

(3)read/wirte information

(4)close the stream

3. FileInputStream用法

 1 package com.test.a;
 2 
 3 import java.io.FileInputStream;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 
 7 public class Test {
 8     public static void main(String args[]) throws IOException {
 9         InputStream is = new FileInputStream("C:\\Users\\hermioner\\Desktop\\test.txt");
10         int length = 0;
11         byte[] buffer = new byte[20];
12         StringBuffer stringBuffer = new StringBuffer();
13         while (-1 != (length = is.read(buffer, 0, 20))) {//一箇中文字元佔兩個位元組
14             stringBuffer.append(new String(buffer, 0, length, "GBK"));// WINDOWS中用ANSI代表,
15             System.out.println(stringBuffer);
16         }
17         System.out.println(stringBuffer);
18         is.close();
19 
20     }
21 }
22 
23 
24 /**
25  * 1.建立一個檔案輸入流 is
26  * 2.建立一個位元組陣列,用它來存放每次讀取到記憶體中的內容,最多讀取20個位元組
27  * 3.必須要加入GBK,否則會亂碼。
28  * 4.讀完以後就關閉流is
29  * 
30  * */
View Code
1 輸出:
2 
3 
4 少年強則國強,國強少
5 少年強則國強,國強少年則更強
6 少年強則國強,國強少年則更強
View Code

test.txt檔案中的內容是:

少年強則國強,國強少年則更強     (note:以ANSI格式儲存的)

4.BufferedInputStream用法

 1 package com.test.a;
 2 
 3 import java.io.BufferedInputStream;
 4 import java.io.FileInputStream;
 5 import java.io.IOException;
 6 
 7 public class Test {
 8     public static void main(String args[]) throws IOException {
 9         FileInputStream fileInputStream=new FileInputStream("C:\\Users\\hermioner\\Desktop\\test.txt");
10         BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);
11         byte buffer[]=new byte[20];
12         int len=0;
13         while((len=bufferedInputStream.read(buffer))!=-1) {
14             System.out.println(new String(buffer,0,len,"GBK"));
15         }
16         
17         bufferedInputStream.close();
18         fileInputStream.close();
19 
20     }
21 }
22 
23 
24 少年強則國強,國強少
25 年則更強
View Code

5. 為什麼需要BufferedInputStream?

BufferedInputStreamBufferedOutputStream這兩個類分別是FilterInputStreamFilterOutputStream的子類,作為裝飾器子類,使用它們可以防止每次讀取/傳送資料時進行實際的寫操作,代表著使用緩衝區。

我們有必要知道不帶緩衝的操作,每讀一個位元組就要寫入一個位元組,由於涉及磁碟的IO操作相比記憶體的操作要慢很多,所以不帶緩衝的流效率很低。帶緩衝的流,可以一次讀很多位元組,但不向磁碟中寫入,只是先放到記憶體裡。等湊夠了緩衝區大小的時候一次性寫入磁碟,這種方式可以減少磁碟操作次數,速度就會提高很多!

同時正因為它們實現了緩衝功能,所以要注意在使用BufferedOutputStream寫完資料後,要呼叫flush()方法或close()方法,強行將緩衝區中的資料寫出。否則可能無法寫出資料。與之相似還BufferedReaderBufferedWriter兩個類。

BufferedInputStreamBufferedOutputStream類就是實現了緩衝功能的輸入流/輸出流。使用帶緩衝的輸入輸出流,效率更高,速度更快。

 四. OutPutStream

1. 常用的位元組輸出流

  • OutputStream
  • FileoutputStream
  • BufferedOutputStream (BufferedOutputStream 不是OutputStream的直接實現子類,是FilterOutputStream的子類)

它們的區別與用途:

(1)OutputStream: 位元組輸出流的基類。在這個類中常用的方法有wirte、close和flush(即重新整理輸出流,把資料馬上寫到輸出流中)

(2)FileOutputStream:用於寫檔案的輸出流

(3)BufferedOutputStream:同BufferedInputStream,可以提高效率。

2. FileOutputStream的用法

 1 package com.test.a;
 2 
 3 import java.io.FileOutputStream;
 4 import java.io.IOException;
 5 
 6 public class Test {
 7     public static void main(String args[]) throws IOException {
 8         FileOutputStream fileOutputStream=new FileOutputStream("C:\\Users\\hermioner\\Desktop\\test.txt",true);
 9         String string="為了中國夢,為了民族的偉大復興,為了老百姓的幸福";
10         byte b[]=string.getBytes();
11         fileOutputStream.write(b);
12         fileOutputStream.close();
13     }
14 }
15 
16 
17 
18 //note:上面的true代表在原來路徑下文字末尾追加欄位,如果不寫或者false則表示在檔案的開頭寫,即完成了覆蓋。如果上面給定的路徑不存在,則會新建立。
View Code

3.BufferedOutputStream的用法

 1 public class Test {
 2     public static void main(String args[]) throws IOException {
 3         FileOutputStream fileOutputStream=new FileOutputStream("C:\\Users\\hermioer\\Desktop\\test.txt");
 4         BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(fileOutputStream);
 5         String string="為了中國夢,為了民族的偉大復興,為了老百姓的幸福";
 6         byte b[]=string.getBytes();
 7         bufferedOutputStream.write(b);
 8         bufferedOutputStream.close();//BufferedOoutputStream中實際上沒有close,呼叫的是父類的close。並且close方法中還呼叫了flush方法
 9     }
10 }
View Code

 

 

參考文獻:

https://www.cnblogs.com/dongguacai/p/5658388.html

https://www.cnblogs.com/progor/p/9357676.html

https://blog.csdn.net/zhaoyanjun6/article/details/54894451