關於Java中<字節流>和<字符流>的操作


  在程序中所有的數據都是以流的方式進行傳輸或者保存的,程序需要數據的時候需要使用輸入流讀取數據,而當程序需要將一些數據保存起來的時候,就要使用輸出流。

  可以通過下面的輸入輸出流關系圖表示這種方式。

  

 

  在java.io包中流的操作主要有字節流字符流兩大類,並且兩個都具備輸入輸出的操作。

  在字節流中輸出數據主要使用OutputStream類完成,輸入則是InputStream類。

  在字符流中輸出數據主要使用Writer類完成,輸入則是Reader類。

  任何一種流接口,它下面都會有多個實現類。下圖展示的是流之間的層次關系圖。

  

 

字節流:

  字節流主要操作byte類型數據,以byte數組為准,主要操作類是OutputStream類和InputStream類。

  1)字節輸出流:OutputStreame

  OutputStream是整個IO包中字節輸出流最大的父類,此類的定義如下:

public abstract class OutputStream extends Object implements Closeable, Flushable

  從這個定義中可以發現,OutputStream類是一個抽象類,如若要使用此類,首先就必須要通過子類來實例化對象。假設現在要操作的事一個文件,則可以使用FileOutputStream類,通過向上轉型后,可以為OutputStream實例化,在OutputStream類中的主要操作方法如下:

1 public void close() throws IOException  //關閉輸出流
2 public void flush() throws IOException  //刷新緩沖區
3 public void write(byte[] b) throws IOException //將一個byte數組寫入數據流
4 public void write(byte[] b,int off,int len) throws IOException //將一個指定范圍的byte數組寫入數據流
5 public abstract void write(int b) throws IOException //將一個字節數據寫入數據流

  此時會用FileOutputStream子類,此類的構造方法如下:

public FileOutputStream(File file) throws FileNotFoundException

  操作時必須接收File類實例,指明要輸出的文件路徑。

  在OutputStream類的定義中可以發現此類實現了Closeable和Flushable兩個接口,這兩個接口的作用從其定義方法中可以得知,Closeable表示可關閉,Flushable表示可刷新,而且在OutputStream類中已經有了這兩個方法的實現,所以操作時一般不會關心這兩個接口,而直接使用OutputStream類就行了。下面舉一個例子:

 1 import java.io.*;
 2 
 3 /**
 4  * Author : Rabbit Yulin
 5  * Created on 2017/2/24 0024 上午 11:10
 6  * Description : 向文件中寫入字符串
 7  */
 8 public class OutputStreamDemo1 {
 9     public static void main(String[] args) throws IOException {
10         /*使用File指定一個文件*/
11         File f = new File("d:"+File.pathSeparator+"test.txt");//申明File對象
12         /*通過子類實例化父類*/
13         OutputStream out;  //輸出對象
14         out = new FileOutputStream(f); //通過對象多態性進行實例化
15         /*寫入操作*/
16         String str = "Hello , World"; //字符串
17         byte b[] = str.getBytes(); //因為只能輸出byte數組,所以將字符串變為byte數組
18         out.write(b);  //將內容輸出
19         /*關閉輸出流*/
20         out.close();
21     }
22 }

  程序運行后可以發現D盤下面已經新增了一個test.txt的文件,打開查看的時候妥妥的內容是:“Hello , World”。上面的代碼在實例化、寫、關閉的時候都會有異常,為了方便起見所以在主方法上直接throws了IOException拋出異常,這樣可以減少try…catch語句。

  可以很清楚的知道一個問題,那就是test.txt文件在程序操作之前是不存在的(當然如果硬是說“我創建了一個”那也沒辦法,反正會被覆蓋掉),程序會自動創建這個文件,並且將內容寫入到這個文件之中。將一個字符串變為byte的數組之后,然后使用write(byte[] b)的方式將byte數組直接寫入到文件中,當然也可以通過循環把每一個字節一個一個地寫入到文件中(其實並沒有什么不同,實現的功能都是一樣的,可以根據喜好隨意),同樣的,下面放出一個Demo:

 1 import java.io.*;
 2 /**
 3  * Author : Rabbit Yulin
 4  * Created on 2017/2/24 0024 上午 11:29
 5  * Description :
 6  */
 7 public class OutputStreamDemo2 {
 8     public static void main(String[] args) throws IOException {
 9         /*File指定一個文件*/
10         File f = new File("d:"+File.pathSeparator+"test2.txt"); //申明對象
11         /*子類實例化父類*/
12         OutputStream out; //輸出對象
13         out = new FileOutputStream(f); //實例化
14         /*寫操作*/
15         String str = "Hello , Again";
16         byte b[] = str.getBytes();
17         for(int i = 0;i<b.length;i++){
18             out.write(b[i]);
19         }
20         /*關閉輸出流*/
21         out.close();
22     }
23 }

  2)追加內容

  剛才有提到過,假若在指定的目錄之下已經有一個同名文件,在程序運行的時候該文件會被覆蓋。一樣的,如果再直接往文本中寫入內容,會造成原有數據的覆蓋。那么此時就可以通過FileOutputStream向文件中追加內容,FileOutputStream的另外一個構造方法:

public FileOutputStream(File file,boolean append) throws FileNotFoundException

  在該構造方法中,如果將append的值設置為true,則表示在文件的末尾追加內容。如果要在文件之后的追加內容,是緊跟在原有的內容之后增加換行,使文件內容顯示更加清晰,則可以使用"\r\n"換行。

  3)字節輸入流 InputStream

  既然程序可以向文件寫入內容,則可以通過InputStream從文件中把數據讀取進程序當中。InputStream類的定義如下:

public abstract class InputStream extends Object implements Closeable

  與OutputStream類一樣,InputStream本身也是一個抽象類,必須依靠子類。如果現在從文件中讀取,子類肯定是FileInputStream。InputStream類中的主要方法如下:

public int availabel() throws IOException //可以取得輸入文件的大小
public void close() throws IOException //關閉輸入流
public abstract int read() throws IOException //讀取內容,以數字方式讀取
public int read(byte[] b) throws IOException //將內容讀到byte數組中同時返回讀入的個數

  通過一個例子來看看如何從文件中讀取內容:

import java.io.*;

/**
 * Author : Rabbit Yulin
 * Created on 2017/2/24 0024 下午 1:46
 * Description :
 */
public class InputStreamDemo1 {
    public static void main(String[] args) throws IOException {
        /*File指定一個文件*/
        File f = new File("d:"+File.pathSeparator+"test.txt"); //申明File文件
        /*子類實例化父類*/
        InputStream is;  //准備一個輸入對象
        is = new FileInputStream(f); //通過對象多態性進行實例化
        /*進行讀操作*/
        byte[] b = new byte[1024]; //所有的內容讀到次數組中
        is.read(b);/*關閉輸入流*/
        is.close();
        System.out.println("內容為:"+new String(b)); //把數組變為字符串
    }
}

  雖然內容都被讀取進來了,但是有一個問題就是打印結果的后面有很多個空格。這是因為byte數組的大小有1024,然而實際的內容只有13個字節,也就是說還存在着1011個空白的弓箭,在將byte數組變為字符串時也將這1011個無用的空間轉為了字符串,這樣的操作肯定是不合理的。如果要想要解決以上的問題,則要觀察read的方法,在次方法上有一個返回值,此返回值表示想數組中寫入了多少個數據。因此把上面的程序修改一下的代碼如下:

 1 import java.io.*;
 2 
 3 /**
 4  * Author : Rabbit Yulin
 5  * Created on 2017/2/24 0024 下午 1:46
 6  * Description :
 7  */
 8 public class InputStreamDemo1 {
 9     public static void main(String[] args) throws IOException {
10         /*File指定一個文件*/
11         File f = new File("d:"+File.pathSeparator+"test.txt"); //申明File文件
12         /*子類實例化父類*/
13         InputStream is;  //准備一個輸入對象
14         is = new FileInputStream(f); //通過對象多態性進行實例化
15         /*進行讀操作*/
16         byte[] b = new byte[1024]; //所有的內容讀到次數組中
17         int len = is.read(b);
18         /*關閉輸入流*/
19         is.close();
20         System.out.println("讀取的數據長度:"+len);
21         System.out.println("內容為:"+new String(b,0,len)); //把數組變為字符串
22     }
23 }

  這樣處理之后的代碼再次運行,發現那些多余的空格就不會再產生了。因為程序在最后只是將byte數組指定范圍中的內容編程了字符串。需要注意的一點是,FileInputStream讀取時如果指定的路徑不存在,則程序會出現異常。

  以上的這個問題解決的方式似乎還是有些不太完美,因為雖然最后指定了byte數組的范圍,但是程序依然開辟了很多的無用空間,這樣肯定會造成資源的浪費,那么此時能否根據根據文件的數據長度來開辟空間大小?查看了API可以得知File類中存在一個length()方法,此方法可以取得文件的大小,來開辟指定的byte數組空間。

 1 import java.io.*;
 2 
 3 /**
 4  * Author : Rabbit Yulin
 5  * Created on 2017/2/24 0024 下午 2:37
 6  * Description :
 7  */
 8 public class InputStreamDemo2 {
 9     public static void main(String[] args) throws IOException {
10         File f = new File("d:"+ File.pathSeparator+"test.txt");
11         InputStream is;
12         is = new FileInputStream(f);
13         byte[] b = new byte[(int)f.length()];
14         is.read(b);
15         is.close();
16         System.out.println("內容為:"+new String(b));
17     }
18 }

  這種讀取的方式其實適用范圍比較小,因為文本數據只要很大,那就造成一些未知的錯誤了。

 

字符流:

  在程序中一個字符等於兩個字節,那么Java提供了Reader和Writer兩個專門操作字符流的類。

  1)字符輸出流 Writer

  Writer 本身是一個字符流的輸出類,此類的定義如下:

public abstract calss Writer extends Object implements Appendable,Closeable,Flushable;

  此類也是一個抽象類,如果要使用這個類則需要使用其子類,這個時候如果要往文件中寫入數據,應該使用FileWriter的子類。Writer類的常用方法如下:

public abstract void close() throws IOException //關閉輸出流
public void write(String str) throws IOException //將字符串輸出
public void write(char[] cbuf) throws IOException //將字符數組輸出
public abstract void flush() throws IOException //強制性清空緩存

  FileWriter類的構造方法定義如下:

public FileWriter(File file) throws IOException

  在Writer類中除了實現Closeable和Flushable兩個接口之外,還實現一個Appendable接口,此接口表示的是內容可以被追加,接受的參數是CharSequence,實際上String類就實現了此接口,所以可以直接通過次接口的方法向輸出流中追加內容。例如:

 1 import java.io.File;
 2 import java.io.FileWriter;
 3 import java.io.IOException;
 4 import java.io.Writer;
 5 
 6 /**
 7  * Author : Rabbit Yulin
 8  * Created on 2017/2/24 0024 下午 3:31
 9  * Description :
10  */
11 public class WriterDemo1 {
12     public static void main(String[] args) throws IOException {
13         File f = new File("d:"+File.pathSeparator+"test.txt");
14         Writer out;
15         out = new FileWriter(f);
16         String str = "Hello,World";
17         out.write(str);
18         out.flush();
19         out.close();
20     }
21 }

  整個代碼看下來和OutputStream沒有太大的區別,唯一的好處就是可以直接輸出字符串,而不用再將字符串變為byte數組之后再輸出。

  2)使用FileWriter追加文件的內容

  在使用字符流操作的時候,也可以實現文件的追加功能,直接使用FileWriter類黃總的一下構造,就可以實現追加:

public FileWriter(File file,boolean append) throws IOException

  將append的值設置為truw,表示追加。

  3)字符輸入流Reader

  Reader是使用字符的方式從文件中取出數據,Reader類的定義如下:

public abstract class Reader extends Object implement Readable,Closeable

  Reader不用說,也是一個抽象類,如果要在從文件中刦內容時,則可以直接使用FileReader子類。Reader類的常用方法:

1 public abstract void close() throws IOException //關閉輸出流
2 public int read() throws IOException //讀取單個字符
3 public int read(char[] cbuf) throws IOException //將內容讀到字符數組內,返回讀入的長度

  FileReader的構造方法定義如下:

public FileReader(File file) throws FileNotFoundException

  以下放出實例來讀取文件中的文本內容

 1 import java.io.*;
 2 
 3 /**
 4  * Author : Rabbit Yulin
 5  * Created on 2017/2/24 0024 下午 3:51
 6  * Description :
 7  */
 8 public class ReaderDemo1 {
 9     public static void main(String[] args) throws IOException {
10         File f = new File("d:"+File.pathSeparator+"test.txt");
11         Reader reader = new FileReader(f);
12         char[] c = new char[1024];
13         int len = reader.read(c);
14         reader.close();
15         System.out.println("內容為:"+new String(c,0,len));
16     }
17 }

  如果此時不知道數據的長度,也可以使用循環的方式進行內容的讀取:

 1 import java.io.*;
 2 
 3 /**
 4  * Author : Rabbit Yulin
 5  * Created on 2017/2/24 0024 下午 3:54
 6  * Description :
 7  */
 8 public class ReaderDemo2 {
 9     public static void main(String[] args) throws IOException {
10         File f = new File("d:"+ File.pathSeparator+"test.txt");
11         Reader reader = new FileReader(f);
12         int len = 0;
13         char[] c = new char[1024];
14         int temp = 0;
15         while((temp = reader.read()) != -1){
16             c[len] = (char)temp;
17             len++;
18         }
19         reader.close();
20         System.out.println("內容為:"+ new String(c,0,len));
21     }
22 }

 

 

 


免責聲明!

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



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