一、明確字符和字節(jié)的概念
字節(jié):1 byte = 8 bit
字符:1 char = 2 byte = 16 bit(java默認(rèn))
在計(jì)算機(jī)硬件層面吼肥,1 bit 是數(shù)據(jù)最小的單位。但是在大多數(shù)情況下,1 bit 存儲(chǔ)的信息太少,我們通常把 1 字節(jié)作為數(shù)據(jù)最小的基本單位杖挣。
而字符實(shí)際上也是對字節(jié)的一種包裝肩榕,那為什么還需要引入字符刚陡?
對于西方世界,使用英語等語種的國家來說株汉,1字節(jié)有 256個(gè)符號編碼筐乳,對于26個(gè)英文字母加上常用的標(biāo)點(diǎn)符號已經(jīng)夠用了。這就是常用的ASCII 碼乔妈。
但是對于東方國家蝙云,中文,日文等文字路召,數(shù)量太多勃刨,1個(gè)字節(jié)根本沒有辦法表示所有的字符,所以引入了Unicode —— 統(tǒng)一編碼股淡,而這種編碼的常規(guī)字符集就是使用2個(gè)字節(jié)身隐,所以引入了字符的概念。
但是唯灵,從根本而言贾铝,一切都是字節(jié)流,字符流也是字節(jié)流的一種形式。
二垢揩、關(guān)于 java中字節(jié)流和字符流
2.1 字節(jié)流玖绿,字符流概念
Java中,讀取數(shù)據(jù)時(shí)叁巨,字節(jié)流的數(shù)據(jù)存儲(chǔ)單位是字節(jié)斑匪,會(huì)使用字節(jié)類型數(shù)組 byte[] 來保存數(shù)據(jù),可以操作字節(jié)锋勺,字節(jié)數(shù)組秤标。
而 字符流的存儲(chǔ)單位是字符,使用字符類數(shù)組 char[] 來保存數(shù)據(jù)宙刘,可以操作字符苍姜,字符數(shù)組或字符串。
2.2 java中的字節(jié)流悬包,字符流相關(guān)API
Java 的I/O庫有兩個(gè)分支:
- 面向字節(jié)流的InputSteam和OutputStream
- 面向字符的Reader 和 wirter
ByteArrayInputStream:把內(nèi)存中的一個(gè)緩沖區(qū)作為 InputStream 使用 .
StringBufferInputStream: 把一個(gè) String 對象作為 InputStream .
FileInputStream:把一個(gè)文件作為 InputStream 衙猪,實(shí)現(xiàn)對文件的讀取操作
PipedInputStream :實(shí)現(xiàn)了 pipe 的概念,主要在線程中使用 . 管道輸入流是指一個(gè)通訊管道的接收端布近。
一個(gè)線程通過管道輸出流發(fā)送數(shù)據(jù)垫释,而另一個(gè)線程通過管道輸入流讀取數(shù)據(jù),這樣可實(shí)現(xiàn)兩個(gè)線程間的通訊撑瞧。
SequenceInputStream :把多個(gè) InputStream 合并為一個(gè) InputStream . “序列輸入流”類允許應(yīng)用程序把幾個(gè)輸入流連續(xù)地合并起來棵譬,
并且使它們像單個(gè)輸入流一樣出現(xiàn)。每個(gè)輸入流依次被讀取预伺,直到到達(dá)該流的末尾订咸。
ByteArrayOutputStream : 把信息存入內(nèi)存中的一個(gè)緩沖區(qū)中 . 該類實(shí)現(xiàn)一個(gè)以字節(jié)數(shù)組形式寫入數(shù)據(jù)的輸出流。
FileOutputStream: 文件輸出流是向 File 或 FileDescriptor 輸出數(shù)據(jù)的一個(gè)輸出流酬诀。
PipedOutputStream: 管道輸出流是指一個(gè)通訊管道的發(fā)送端脏嚷。 一個(gè)線程通過管道輸出流發(fā)送數(shù)據(jù),
而另一個(gè)線程通過管道輸入流讀取數(shù)據(jù)瞒御,這樣可實(shí)現(xiàn)兩個(gè)線程間的通訊父叙。
CharArrayReader :與 ByteArrayInputStream 對應(yīng)此類實(shí)現(xiàn)一個(gè)可用作字符輸入流的字符緩沖區(qū)
StringReader : 與 StringBufferInputStream 對應(yīng)其源為一個(gè)字符串的字符流。
FileReader : 與 FileInputStream 對應(yīng)
PipedReader :與 PipedInputStream 對應(yīng)
CharArrayWrite : 與 ByteArrayOutputStream 對應(yīng)
StringWrite :無與之對應(yīng)的以字節(jié)為導(dǎo)向的 stream
FileWrite : 與 FileOutputStream 對應(yīng)
PipedWrite :與 PipedOutputStream 對應(yīng)
2.3 字符流肴裙,字節(jié)流API的使用
字節(jié)流示例
//字節(jié)流寫文件
public static void writeFile(){
String str = "采用數(shù)據(jù)流方式(字節(jié)流)寫文件趾唱!";
try{
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D://hello.txt",true));
//需要轉(zhuǎn)化為字節(jié)
byte[] data = str.getBytes();
bos.write(data);
bos.close();
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//字節(jié)流讀文件
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();
}
}
三、字節(jié)流和字符流的區(qū)別
字節(jié)流和字符流的區(qū)別:
- 字節(jié)流在操作文件時(shí)蜻懦,本身不會(huì)用到緩沖區(qū)(內(nèi)存)甜癞,是對文件本身直接操作的;而字符流在操作時(shí)是使用到緩沖區(qū)的阻肩。
- 字節(jié)流在操作文件時(shí)带欢,即使不關(guān)閉資源(close)文件也能輸出运授;字符流如果不是用close方法的話,則不會(huì)輸出任何內(nèi)容乔煞,說明字符流使用了緩沖區(qū)吁朦。且可以使用flush方法強(qiáng)制進(jìn)行刷新緩沖區(qū),此時(shí)在不close情況下也能輸出內(nèi)容渡贾。
- Reader類的read()方法返回類型是int逗宜,占兩個(gè)字節(jié),如果到達(dá)流的末尾空骚,則返回-1纺讲;inputStream的read()方法雖然也返回int,打算面向字節(jié)流囤屹,占一個(gè)字節(jié)熬甚。因此對于超過一個(gè)字節(jié)的只能使用字符流來讀取,如漢字肋坚。
- 處理方式不同乡括;字節(jié)流:處理字節(jié)和字節(jié)數(shù)組成的二進(jìn)制對象。
字符流:處理字符智厌,字符數(shù)或字符串诲泌。
注:緩沖區(qū)是什么?铣鹏?
緩沖區(qū)可以理解為一段特殊的內(nèi)存敷扫。
在某些情況下秽澳,如果程序頻繁操作一個(gè)資源颂龙,則性能會(huì)很低,為了提升性能涂臣,可以將這部分?jǐn)?shù)據(jù)暫時(shí)讀入內(nèi)存的一塊區(qū)域惨险,之后就可以直接從內(nèi)存中讀取數(shù)據(jù)羹幸,提升速度和性能脊髓。
四辫愉、使用場景判斷
4.1 數(shù)據(jù)格式
- 二進(jìn)制格式(不能確定是純文本):字節(jié)流,InputStream将硝、OutputStream及其子類恭朗。
- 純文本格式(含中英文或其他編碼方式):字符流,Reader依疼,Writer及其子類痰腮。
4.2 數(shù)據(jù)來源
- 文件:字節(jié)流 FileInputStream,F(xiàn)ileOutputStream律罢;字符流 FileReader膀值,F(xiàn)ileWriter
- byte[]: 字節(jié)流 ByteArrayInputStream, ByteArrayOutputStream char[]:字符流
- CharArrayReader, CharArrayWriter String: 字節(jié)
- StringBufferInputStream, StringBufferOuputStream 棍丐;字符流 StringReader,StringWriter
- 網(wǎng)絡(luò)數(shù)據(jù)流:字節(jié)流 InputStream, OutputStream;字符流 Reader, Writer
4.3 是否需要格式化輸出
需要格式化輸出的:PrintStream, PrintWriter
4.4 是否需要緩沖
需要緩沖:字節(jié)流 BufferedInputStream, BufferedOutputStream沧踏;字符流 BufferedReader, BufferedWriter
4.5 輸入還是輸出
- 輸入:Reader, InputStream 類型的子類
- 輸出:Writer, OutputStream 類型的子類
4.6 是否有流轉(zhuǎn)化
- 字節(jié)到字符:InputStreamReader
- 字符到字節(jié):OutputStreamWriter
4.7 特殊需要
- 對象輸入輸出:ObjectInputStream, ObjectOutputStream
- 進(jìn)程間通信:PipedInputStream, PipedOutputStream, PipedReader, PipedWriter
- 合并輸入: SequenceInputStream