一、明確字符和字節的概念
字節:1 byte = 8 bit
字符:1 char = 2 byte = 16 bit(java默認)
在計算機硬件層面,1 bit 是數據最小的單位。但是在大多數情況下,1 bit 存儲的信息太少,我們通常把 1 字節作為數據最小的基本單位。
而字符實際上也是對字節的一種包裝,那為什么還需要引入字符?
對于西方世界,使用英語等語種的國家來說,1字節有 256個符號編碼,對于26個英文字母加上常用的標點符號已經夠用了。這就是常用的ASCII 碼。
但是對于東方國家,中文,日文等文字,數量太多,1個字節根本沒有辦法表示所有的字符,所以引入了Unicode —— 統一編碼,而這種編碼的常規字符集就是使用2個字節,所以引入了字符的概念。
但是,從根本而言,一切都是字節流,字符流也是字節流的一種形式。
二、關于 java中字節流和字符流
2.1 字節流,字符流概念
Java中,讀取數據時,字節流的數據存儲單位是字節,會使用字節類型數組 byte[] 來保存數據,可以操作字節,字節數組。
而 字符流的存儲單位是字符,使用字符類數組 char[] 來保存數據,可以操作字符,字符數組或字符串。
2.2 java中的字節流,字符流相關API
Java 的I/O庫有兩個分支:
- 面向字節流的InputSteam和OutputStream
- 面向字符的Reader 和 wirter
ByteArrayInputStream:把內存中的一個緩沖區作為 InputStream 使用 .
StringBufferInputStream: 把一個 String 對象作為 InputStream .
FileInputStream:把一個文件作為 InputStream ,實現對文件的讀取操作
PipedInputStream :實現了 pipe 的概念,主要在線程中使用 . 管道輸入流是指一個通訊管道的接收端。
一個線程通過管道輸出流發送數據,而另一個線程通過管道輸入流讀取數據,這樣可實現兩個線程間的通訊。
SequenceInputStream :把多個 InputStream 合并為一個 InputStream . “序列輸入流”類允許應用程序把幾個輸入流連續地合并起來,
并且使它們像單個輸入流一樣出現。每個輸入流依次被讀取,直到到達該流的末尾。
ByteArrayOutputStream : 把信息存入內存中的一個緩沖區中 . 該類實現一個以字節數組形式寫入數據的輸出流。
FileOutputStream: 文件輸出流是向 File 或 FileDescriptor 輸出數據的一個輸出流。
PipedOutputStream: 管道輸出流是指一個通訊管道的發送端。 一個線程通過管道輸出流發送數據,
而另一個線程通過管道輸入流讀取數據,這樣可實現兩個線程間的通訊。
CharArrayReader :與 ByteArrayInputStream 對應此類實現一個可用作字符輸入流的字符緩沖區
StringReader : 與 StringBufferInputStream 對應其源為一個字符串的字符流。
FileReader : 與 FileInputStream 對應
PipedReader :與 PipedInputStream 對應
CharArrayWrite : 與 ByteArrayOutputStream 對應
StringWrite :無與之對應的以字節為導向的 stream
FileWrite : 與 FileOutputStream 對應
PipedWrite :與 PipedOutputStream 對應
2.3 字符流,字節流API的使用
字節流示例
//字節流寫文件
public static void writeFile(){
String str = "采用數據流方式(字節流)寫文件!";
try{
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D://hello.txt",true));
//需要轉化為字節
byte[] data = str.getBytes();
bos.write(data);
bos.close();
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//字節流讀文件
public static void readFile(){
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D://hello.txt"));
byte[] data = new byte[1024];
int n = -1;
while((n=bis.read(data,0,data.length))!=-1){
String str = new String(data,0,n,"UTF-8");
System.out.println(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
字符流示例
//字符流寫文件
public static void writeFile(){
File file = new File("D:\\hello.txt");
String str = " hello, everybody! welcome to the study of Java!";
try{
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(str);
bw.close();
fw.close();
}catch(IOException e){
e.printStackTrace();
}
}
//字符流讀文件
public static void readerFile(){
File file = new File("D:\\hello.txt");
try{
BufferedReader br = new BufferedReader(new FileReader(file));
String str = null;
while( (str = br.readLine()) != null){
System.out.println(str);
}
br.close();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
三、字節流和字符流的區別
字節流和字符流的區別:
- 字節流在操作文件時,本身不會用到緩沖區(內存),是對文件本身直接操作的;而字符流在操作時是使用到緩沖區的。
- 字節流在操作文件時,即使不關閉資源(close)文件也能輸出;字符流如果不是用close方法的話,則不會輸出任何內容,說明字符流使用了緩沖區。且可以使用flush方法強制進行刷新緩沖區,此時在不close情況下也能輸出內容。
- Reader類的read()方法返回類型是int,占兩個字節,如果到達流的末尾,則返回-1;inputStream的read()方法雖然也返回int,打算面向字節流,占一個字節。因此對于超過一個字節的只能使用字符流來讀取,如漢字。
- 處理方式不同;字節流:處理字節和字節數組成的二進制對象。
字符流:處理字符,字符數或字符串。
注:緩沖區是什么??
緩沖區可以理解為一段特殊的內存。
在某些情況下,如果程序頻繁操作一個資源,則性能會很低,為了提升性能,可以將這部分數據暫時讀入內存的一塊區域,之后就可以直接從內存中讀取數據,提升速度和性能。
四、使用場景判斷
4.1 數據格式
- 二進制格式(不能確定是純文本):字節流,InputStream、OutputStream及其子類。
- 純文本格式(含中英文或其他編碼方式):字符流,Reader,Writer及其子類。
4.2 數據來源
- 文件:字節流 FileInputStream,FileOutputStream;字符流 FileReader,FileWriter
- byte[]: 字節流 ByteArrayInputStream, ByteArrayOutputStream char[]:字符流
- CharArrayReader, CharArrayWriter String: 字節
- StringBufferInputStream, StringBufferOuputStream ;字符流 StringReader,StringWriter
- 網絡數據流:字節流 InputStream, OutputStream;字符流 Reader, Writer
4.3 是否需要格式化輸出
需要格式化輸出的:PrintStream, PrintWriter
4.4 是否需要緩沖
需要緩沖:字節流 BufferedInputStream, BufferedOutputStream;字符流 BufferedReader, BufferedWriter
4.5 輸入還是輸出
- 輸入:Reader, InputStream 類型的子類
- 輸出:Writer, OutputStream 類型的子類
4.6 是否有流轉化
- 字節到字符:InputStreamReader
- 字符到字節:OutputStreamWriter
4.7 特殊需要
- 對象輸入輸出:ObjectInputStream, ObjectOutputStream
- 進程間通信:PipedInputStream, PipedOutputStream, PipedReader, PipedWriter
- 合并輸入: SequenceInputStream