I/O流——字節流


流的概念

流是一個很形象的概念,當程序需要讀取數據的時候,就會開啟一個通向數據源的流,這個數據源可以使文件,內存,或是網絡連接。類似的,當程序需要寫入數據的時候,就會開啟一個通向目的地的流。這時候你就可以想象數據好像在這其中“流”動一樣。

流的分類

①   流按其流向分為“輸入流”和“輸出流”。

②   流按數據傳輸單位分為“字節流”和“字符流”。

a)         “字節流”用來讀寫8位二進制的字節。

b)         “字符流”用來讀寫16位二進制字符。

③   流按功能分為“節點流”和“過濾流”。

a)         “節點流”用於直接操作目標設備的流。例如:磁盤或一塊內存區域。

b)         “過濾流”是對一個已存在的流的鏈接和封裝,通過對數據進行處理為程序提供功能強大、靈活的讀寫功能。

 

字節流

字節流類用於向字節流讀取8位二進制的字節。一般地,字節流主要用於讀寫諸如圖像或聲音等二進制數據。

字節流類以InputStream和OutputStream為頂層類。它們都是抽象類。

一、InputStream

①     InputStream是定義了字節輸入流的抽象類。

②     InputStream中定義的方法

a)         public abstract int read()

b)         public int read(byte[] b)

c)         public int read(byte[] b,int off,int len)

d)         public long skip(long n)

e)         public int available()

f)          public void close()

二、OutputStream

① OutputStream是定義了字節輸出流的抽象類。

② 該類所有方法返回void值,在出錯情況下拋IOException異常

③ OutputStream中定義的方法

g)         public abstract void write(int b)

h)         public void write(byte[] b)

i)           public void write(byte[] b,int off,int len)

j)           public void flush()

k)         public void close()

 

每個抽象類都有多個具體的子類,這些子類對不同的外設進行處理,例如磁盤文件,網絡連接,甚至是內存緩沖區。

三、FileInputStream

① FileInputStream類表示能從文件讀取字節的InputStream類

② 構造方法

a)         FileInputStream(String filePath)

b)         FileInputStream(File fileObj)

四、FileOutputStream

① FileOutputStream表示能向文件寫入字節的OutputStream類

② 構造方法

a)         FileOutputStream(String filePath)

b)         FileOutputStream(File fileObj)

c)         FileOutputStream(String filePath,boolean append)

示例:拷貝指定文件到指定目錄

 1 class FileCopyUtil {  2     public static void copyFile(File src, File dst) throws IOException {  3         FileInputStream fis = new FileInputStream(src);  4         FileOutputStream fos = new FileOutputStream(dst);  5         long time1 = System.currentTimeMillis();  6         int data = -1;  7         while ((data = fis.read()) != -1) {  8  fos.write(data);  9  } 10  fis.close(); 11  fos.close(); 12         long time2 = System.currentTimeMillis(); 13         System.out.println("復制完成,共花費:" + (time2 - time1) + "毫秒"); 14  } 15 }

主方法:

1         try { 2             FileCopyUtil.copyFile(new File("d:/zhangsan/tu.png"), new File("e:/fuzhi.png")); 3         } catch (IOException e) { 4  e.printStackTrace(); 5         }

輸出結果

復制完成,共花費:1545毫秒

單一張71K的圖片就花費了1545毫秒,由此可見效率是極低的,因為它是讀一個寫一個,我們可以換種思路,先全部讀到一個緩沖區,再將內容一次性寫入。這里就好比喝水時一滴一滴地喝還是接到杯子里再喝。

改造下方法,如下:

 1 class FileCopyUtil {  2     public static void copyFile(File src, File dst) throws IOException {  3         FileInputStream fis = new FileInputStream(src);  4         FileOutputStream fos = new FileOutputStream(dst);  5         byte[] buff = new byte[1024 * 1024];// 創建一個1M大小的緩沖區,用來存放輸入流中的字節
 6         int len = 0;// 用來保存實際讀到的字節數
 7         long time1 = System.currentTimeMillis();  8         while ((len = fis.read(buff)) != -1) {  9             fos.write(buff, 0, len); 10  } 11  fis.close(); 12  fos.close(); 13         long time2 = System.currentTimeMillis(); 14         System.out.println("復制完成,共花費:" + (time2 - time1) + "毫秒"); 15  } 16 }

同樣讀取那張圖片,輸出結果:

復制完成,共花費:3毫秒

再復制一個8M的mp3格式文件,輸出結果:

復制完成,共花費:39毫秒

 

五、ByteArrayInputStream

①ByteArrayInputStream是把字節數組當成源的輸入流。

②兩個構造方法,每個都需要一個字節數組提供數據源:

a)       ByteArrayInputStream(byte array[])

b)       ByteArrayInputStream(byte array[],int start,int numBytes)

1         String str="hello,HangZhou"; 2         ByteArrayInputStream bis=new ByteArrayInputStream(str.getBytes()); 3         int data=-1; 4         while((data=bis.read())!=-1) 5  { 6             System.out.println((char)data); 7         }

輸出結果:

h e l l o , H a n g Z h o u

 

六、ByteArrayOutputStream

①ByteArrayOutputStream是把字節數組當作目標的輸出流。

②兩個構造方法:

a)       ByteArrayOutputStream()

創建一個新的byte數組輸出流

b)       ByteArrayOutputStream(int numBytes)

創建一個新的byte數組輸出流,具有指定大小緩沖區(字節為單位)

 1         ByteArrayOutputStream bos = new ByteArrayOutputStream();  2         bos.write(97);  3         bos.write(65);  4         try {  5             bos.write("hello,word".getBytes());  6         } catch (IOException e) {  7  e.printStackTrace();  8  }  9         byte[] buff = bos.toByteArray(); 10         for (byte b : buff) { 11             System.out.print((char)data+" "); 12  } 13 
14         FileOutputStream fos=new FileOutputStream("d://aa.txt", true); 15         bos.writeTo(fos);//把ByteArrayOutputStream內部緩沖區的數據寫到對應的文件輸出流中
16         fos.close();

輸出結果:

aAhello,word

並會在d盤下創建一個aa.txt文件,里面內容為輸出結果的內容,再次執行將追加一次執行結果的內容。

 

過濾流

① 過濾流僅僅是為底層透明地提供擴展功能的輸入流(輸出流)的包裝。這些流一般由普通類的方法(即過濾流的一個父類)訪問。

② 過濾字節流FilterInputStream和FilterOutputStream。構造方法:

a)  FilterInputStream(InputStream is)

b)  FilterOutputStream(OutputStream os)

③ 這些類提供的方法和InputStream及OutputStream類的方法相同。

④ 常用的過濾流BufferedInputStream和BufferedOutputStream,DataInputStream和DataOutputStream

 

BufferedInputStream,BufferedOutputStream用法舉例

使用過濾流來改寫上面的復制方法

 1 class FileUtil {  2     public static void copyFile(File src, File dst) throws IOException {  3         FileInputStream fis = new FileInputStream(src);  4         FileOutputStream fos = new FileOutputStream(dst);  5         BufferedInputStream bis=new BufferedInputStream(fis);  6         BufferedOutputStream bos=new BufferedOutputStream(fos);  7         
 8         int data = 0;// 用來保存實際讀到的字節數
 9         long time1 = System.currentTimeMillis(); 10         while ((data = bis.read()) != -1) { 11  bos.write(data); 12  } 13  bis.close(); 14  bos.close(); 15         long time2 = System.currentTimeMillis(); 16         System.out.println("復制完成,共花費:" + (time2 - time1) + "毫秒"); 17  } 18 }

主方法:

1         try { 2             FileUtil.copyFile(new File("d:/zhangsan/Closer To Me.mp3"), new File( 3                     "e:/fuzhi.mp3")); 4         } catch (IOException e) { 5  e.printStackTrace(); 6  } 7     }

復制同樣的一首歌,輸出結果:

復制完成,共花費:905毫秒

時間增加了很多,但也比文件直接讀寫快了不少。Buffered中自帶一個8k左右的緩沖區。

 

DataInputStream和DataOutputStream用法舉例:

寫入文件:

 1         String name="zhangsan";  2         int age=10;  3         boolean flag=true;  4         char sex='男';  5         double money=123.45;  6         
 7         DataOutputStream dos=new DataOutputStream(new FileOutputStream("d:/b.txt"));  8  dos.writeUTF(name);  9  dos.writeInt(age); 10  dos.writeBoolean(flag); 11  dos.writeChar(sex); 12  dos.writeDouble(money); 13         dos.close();

打開b.txt后發現有亂碼,那是因為寫進去的是二進制

 

讀文件:

1         DataInputStream dis=new DataInputStream(new FileInputStream("d:/b.txt")); 2         //讀的順序必須與寫入的順序一致
3  System.out.println(dis.readUTF()); 4  System.out.println(dis.readInt()); 5  System.out.println(dis.readBoolean()); 6  System.out.println(dis.readChar()); 7  System.out.println(dis.readDouble()); 8         dis.close();

輸出結果:

zhangsan

10

true

123.45

 

過濾流總結:

BufferedInputStream與BufferedOutputStream

需要使用已經存在的節點流來構造,提供緩沖的讀寫,提高了讀寫的效率。

DataInputStream與DataOutputStream

數據輸入輸出流允許應用程序讀寫基本Java數據類型。應用程序可以使用數據輸出流寫入,稍后由數據輸入流讀取。讀寫順序要保持一致。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM