Java FileInputStream與FileReader的區別


在解釋Java中FileInputStream和FileReader的具體區別之前,我想講述一下Java中InputStream和Reader的根本差異,以及分別什么時候使用InputStream和Reader。實際上, InputStream和Reader都是抽象類,並不直接地從文件或者套接字(socket)中讀取數據。然而,它們之間的主要差別在於:InputStream用於讀取二進制數據(字節流方式,譯者注),Reader用於讀取文本數據(字符流方式,譯者注),准確地說,Unicode字符。那么,二進制數據和文本數據的區別是什么呢?當然,所有讀取的東西本質上是字節,然后需要一套字符編碼方案,把字節轉換成文本。Reader類使用字符編碼來解碼字節,並返回字符給調用者。Reader類要么使用運行Java程序平台的默認字符編碼,要么使用Charset對象或者String類型的字符編碼名稱,如“UTF-8”。盡管它是一個最簡單的概念,當讀取文本文件或從套接字中讀取文本數據時,很多Java開發者會因沒有指定字符編碼而犯錯。記住,如果你沒有指定正確的編碼,或者你的程序沒有使用的協議中已存在的字符編碼,如HTML的 “Content-Type(內容類型)”、XML文件頭指定的編碼,你可能無法正確地讀取的所有數據。一些不是默認編碼呈現的字符,可能變成“?”或小方格。一旦你知道stream和reader之間的根本區別,理解FileInputStream和FileReader之間的差異就很容易了。既可以讓你從文件中讀取數據,然而FileInputStream用於讀取二進制數據,FileReader用來讀取字符數據。

Java中FileReader vs FileInputStream

由於FileReader類繼承了InputStreamReader類,使用的字符編碼,要么由類提供,要么是平台默認的字符編碼。請記住,InputStreamReader會緩存的字符編碼。創建對象后,設置字符編碼將不會有任何影響。讓我們來看看如何使用Java中InputStream和FileReader的例子。你可以提供任何一個文件對象或一個包含文件位置的字符串,以開始讀取文件的字符數據。這類似於FileInputStream,也提供了類似的用於讀取文件源的構造函數。盡管建議使用BufferedReader來讀取文件數據。我把我的eclipse的file.encoding設置成了UTF-8,然后再c盤新建一個data.txt並且輸入一個永字,用記事本打開另存為UTF-8編碼。這個時候我們在eclipse中運行程序,可以看到data.txt的打印二進制內容是efbbbfe6b0b8(通過Notepad++的HEX-Editor插件查看data.txt文件十六進制內容可以驗證這一點),說明FileInputStream沒有進行任何編碼轉換把data.txt的二進制內容讀入java變量中。我們再來看下面一行輸出  feff6c38永  就會發現FileReader通過UTF-8讀取文件,然后對文件進行了編碼,使其轉換成unicode編碼存入java變量中,這樣才能在java中正確使用,因為java存儲在內存里的變量都是unicode編碼。如果我們把data.txt另存為ANSI(GBK)編碼,FileReader還是通過UTF-8讀取文件,然后對文件進行了unicode編碼就會出現亂碼問題。如果把eclipse的file.encoding設置成了GBK再運行程序就會打印正常,如下

d3c0
6c38永

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.awt.Color;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
 
/**
  * Java程序通過字節流和字符流的方式來讀取文件數據。
  * 需強調FileInputStream和FileReader的關鍵區別在於:FileReader用於讀取字符流,而FileInputStream用來讀取原始字節流。
  * @author Javin Paul
  */
public class HowToReadFileInJava {
     public static void main(String args[]) {
 
         // 例1 – 使用FileInputStream 讀取文件內容
         try (FileInputStream fis = new FileInputStream( "c:/data.txt" )) {
             int data = fis.read();
             while (data != - 1 ) {
                 System.out.print(Integer.toHexString(data));
                 data = fis.read();
             }
         } catch (IOException e) {
             System.out.println( "Failed to read binary data from File" );
             e.printStackTrace();
         }
 
            System.out.println();
         // 例2 – Java中使用FileReader 讀取文件數據
         try (FileReader reader = new FileReader( "c:/data.txt" )) {
             int character = reader.read();
             while (character != - 1 ) {
                        System.out.print(Integer.toHexString(character));
                 System.out.print(( char ) character);
                 character = reader.read();
             }
         } catch (IOException io) {
             System.out.println( "Failed to read character data from File" );
             io.printStackTrace();
         }
     }
}

另存為UTF-8輸出:

1
2
3
4
5

UTF-8
efbbbfe6b0b8
feff6c38永

 

另存為ANSI(GBK)輸出:

 
1
2
3
4
5

UTF-8
d3c0
fffd�fffd�

第1個例子是按字節從文件中讀取數據,因此勢必會非常慢。FileInputStream的read() 方法是阻塞式的,讀取字節或數據塊,直到無數據輸入。它要么返回數據的下一個字節,當到達文件末尾時,返回-1。這意味着,我們每循環讀取一個字節,將其打印為十六進制字符串。順便說一句,將InputStream轉換成字節數組是可選的。另一方面,例2是按字符讀取數據。繼承自FileReader的InputStreamReader 的read() 方法讀取單個字符,並返回該字符,當到達流末尾時,返回-1。這就是為什么你看到例2輸出的文字跟文件中的完全一樣。

這就是所有關於Java中FileInputStream和FileReader之間的區別。歸根結底:使用FileReader或BufferedReader從文件中讀取字符或文本數據,並總是指定字符編碼;使用FileInputStream從Java中文件或套接字中讀取原始字節流。


免責聲明!

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



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