本文包含以下知識點(diǎn):
- [x] 字節(jié)流OutputStream和InputStream類及其子類
- [x] 字符流Writer和Reader類及其子類
- [x] 轉(zhuǎn)換流OutputStreamWriter和InputStreamReader
- [x] 代碼示例
- [x] 字節(jié)流笼呆、字符流的比較
- [x] 各類的使用場景
流
在程序中所有的數(shù)據(jù)都是以流的方式進(jìn)行傳輸和保存的。程序需要數(shù)據(jù)的時(shí)候要使用輸入流讀取數(shù)據(jù)旨别,而當(dāng)程序需要將一些數(shù)據(jù)保存起來的時(shí)候诗赌,就要使用輸出流完成。
在java.io包中操作文件內(nèi)容的主要有兩大類:字節(jié)流秸弛、字符流铭若。兩類都分為輸入和輸出操作洪碳。輸入流基本方法是讀,輸出流基本方法是寫叼屠。
大致操作流程:(以File為例)
- 使用File類打開一個(gè)文件瞳腌;
- 通過字節(jié)流或字符流的子類,指定輸出的位置镜雨;
- 進(jìn)行讀/寫操作嫂侍;
- 關(guān)閉輸入/輸出。
java中的流是對字節(jié)序列的抽象荚坞,流中保存的實(shí)際上全都是字節(jié)文件挑宠。
字節(jié)流
字節(jié)流處理的基本單元為1個(gè)字節(jié)(byte),操作字節(jié)和字節(jié)數(shù)組颓影,通常用來處理二進(jìn)制數(shù)據(jù)各淀。
面向字節(jié)流的OutputStream和InputStream是一切的基礎(chǔ)。均為抽象類诡挂,實(shí)際使用的是它們的一系列子類碎浇。
字節(jié)輸出流OutputStream
類與方法定義
抽象類,定義如下:
public abstract class OutputStream
implements Closeable, Flushable {}
//Closeable表示可關(guān)閉咆畏,F(xiàn)lushable表示刷新南捂,清空內(nèi)存中的數(shù)據(jù)
方法有:
1.將一個(gè)字節(jié)數(shù)據(jù)寫入數(shù)據(jù)流
public abstract void write(int b) throws IOException;
2.將一個(gè)byte數(shù)組寫入數(shù)據(jù)流
public void write(byte b[]) throws IOException
3.將指定byte數(shù)組中從偏移量off開始的len個(gè)字節(jié)寫入數(shù)據(jù)流
public void write(byte b[], int off, int len) throws IOException
4.刷新緩沖區(qū)
public void flush() throws IOException {}
5.關(guān)閉輸出流
public void close() throws IOException {}
要想使用此類及以上方法吴裤,必須通過子類實(shí)例化對象旧找。
繼承OutputStream的子類
FileOutputStream
文件輸出流,是向File或FileDescriptor輸出數(shù)據(jù)的一個(gè)輸出流麦牺。
FileOutputStream類的構(gòu)造方法有:
1.創(chuàng)建一個(gè)文件輸出流钮蛛,向指定的File對象輸出數(shù)據(jù)(寫入)
public FileOutputStream(File file) throws FileNotFoundException
//字節(jié)寫到文件的開始,輸出會進(jìn)行覆蓋
public FileOutputStream(File file, boolean append) throws FileNotFoundException
//如果append設(shè)為true剖膳,字節(jié)將寫到文件末尾
2.創(chuàng)建一個(gè)文件輸出流魏颓,向指定名稱的文件輸出數(shù)據(jù)(寫入到指定名稱的文件中)
public FileOutputStream(String name) throws FileNotFoundException
//輸出會進(jìn)行覆蓋
public FileOutputStream(String name, boolean append)
throws FileNotFoundException
//如果append設(shè)為true,字節(jié)將寫到文件末尾
3.創(chuàng)建一個(gè)文件輸出流吱晒,向指定的文件描述器輸出數(shù)據(jù)甸饱,該文件描述符表示文件系統(tǒng)中一個(gè)實(shí)際文件的現(xiàn)有連接。
public FileOutputStream(FileDescriptor fdObj)
OutputStream的其他子類
1.ObjectOutputStream(對象輸出流)
對象輸出流將Java對象的原始數(shù)據(jù)類型和對象圖寫入輸出流仑濒。只有支持可序列化接口的對象才可以寫入到輸出流叹话。
2.ByteArrayOutputStream(字節(jié)數(shù)組輸出流)
該類實(shí)現(xiàn)了一個(gè)以字節(jié)數(shù)組形式寫入數(shù)據(jù)的輸出流,緩沖區(qū)會隨著數(shù)據(jù)的寫入而自動擴(kuò)大墩瞳⊥蘸可以用toByteArray()和toString()檢索數(shù)據(jù)。
構(gòu)造方法有:
(1)創(chuàng)建一個(gè)新的字節(jié)數(shù)組輸出流
public ByteArrayOutputStream() {
this(32);}
//緩沖區(qū)容量最初是32字節(jié)喉酌,如果需要热凹,大小會增加
(2)創(chuàng)建一個(gè)新的字節(jié)數(shù)組輸出流泵喘,并帶有制定大小字節(jié)的緩沖區(qū)容量
public ByteArrayOutputStream(int size)
3.PipedOutputStream(管道輸出流)
管道輸出流可以連接到管道輸入流來創(chuàng)建通信管道,它是這個(gè)管道的發(fā)送端般妙。
一個(gè)線程通過管道輸出流寫入(發(fā)送)數(shù)據(jù)纪铺,另一個(gè)線程通過管道輸入流讀取數(shù)據(jù),這樣可實(shí)現(xiàn)兩個(gè)線程之間的通訊股冗。
不建議嘗試從單個(gè)線程使用這兩個(gè)管道流對象霹陡,因?yàn)樗赡軙斐删€程死鎖。
構(gòu)造方法有:
(1)創(chuàng)建連接到指定管道輸入流的管道輸出流
public PipedOutputStream(PipedInputStream snk) throws IOException
(2)創(chuàng)建一個(gè)管道輸出流止状,該輸出流尚未連接到管道輸入流
public PipedOutputStream()
4.FilterOutputStream
其子類有DataOutputStream烹棉、BufferedOutputStream、PrintStream怯疤。
代碼示例:將序列化對象寫入文件
創(chuàng)建文件浆洗,輸出字節(jié)的代碼示例:
public class Test {
public static void main(String[] args) {
try {
File f = new File("E:/test1.txt");
//如果文件不存在,會自動創(chuàng)建出來
FileOutputStream fs = new FileOutputStream(f);
//如果想在文件中執(zhí)行追加集峦,構(gòu)造方法中append設(shè)為true
String str = "Hello World!";
byte[] b = str.getBytes();
//因?yàn)槭亲止?jié)流伏社,先將字符串轉(zhuǎn)化為字節(jié)數(shù)組
fs.write(b);
//這里也可以一個(gè)字節(jié)一個(gè)字節(jié)進(jìn)行輸出
//for(int i=0;i<b.length;i++){fs.write([i]);}
fs.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
將序列化對象寫入文件,會用到字節(jié)輸出流:
/**
* 將序列化對象存儲到文件
*/
public class Test {
public static void main(String[] args) {
//創(chuàng)建一個(gè)Use對象
User user = new User(1, "amy");
//創(chuàng)建一個(gè)List對象
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("I am");
list.add("amy");
try {
FileOutputStream fs = new FileOutputStream("E:/test.ser");
//如果文件不存在塔淤,會自動創(chuàng)建出來
ObjectOutputStream os = new ObjectOutputStream(fs);
//ObjectOutputStream能讓寫入對象摘昌,但無法直接連接文件,所以需要參數(shù)指引
os.writeObject(user);
os.writeObject(list);
//寫入對象
os.close();
//關(guān)閉ObjectOutputStream
} catch (IOException ex) {
ex.printStackTrace();
}catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
public class User implements Serializable {
//User類實(shí)現(xiàn)序列化
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
如下圖所示
字節(jié)輸入流InputStream
類與方法定義
抽象類高蜂,定義如下:
public abstract class InputStream implements Closeable
方法有:
1.讀取一個(gè)字節(jié)無符號填充到int的低8位聪黎,高8位補(bǔ)零,讀取到-1結(jié)束
public abstract int read() throws IOException;
//read()返回讀取的字節(jié)或-1(-1表示讀取結(jié)束)
2.將當(dāng)前輸入流中b.length個(gè)字節(jié)讀入到byte數(shù)組中备恤,實(shí)際讀取的字節(jié)數(shù)作為整數(shù)返回
public int read(byte b[]) throws IOException
3.將輸入流中l(wèi)en個(gè)字節(jié)數(shù)據(jù)讀入一個(gè)字節(jié)數(shù)組中稿饰,從數(shù)組的off位置開始存放len長度的數(shù)據(jù)
public int read(byte b[], int off, int len) throws IOException
//帶有參數(shù)的read方法返回的是讀取字節(jié)數(shù)或-1,內(nèi)部也在調(diào)用read(),讀取字節(jié)
4.從該輸入流中跳過或忽略n字節(jié)
public long skip(long n) throws IOException
5.返回這個(gè)輸入流中可讀(或跳過)的字節(jié)數(shù)估計(jì)值露泊,即可取得輸入文件的大小
public int available() throws IOException
6.關(guān)閉輸入流
public void close() throws IOException
要想使用此類及以上方法喉镰,必須通過子類實(shí)例化對象。
繼承InputStream的子類
FileInputStream
文件輸入流惭笑,從文件系統(tǒng)中的文件讀取輸入字節(jié)侣姆。
FileInputStream的構(gòu)造方法有:
1.創(chuàng)建一個(gè)輸入文件流,從指定的File對象讀取數(shù)據(jù)
public FileInputStream(File file) throws FileNotFoundException
2.創(chuàng)建一個(gè)輸入文件流沉噩,從指定名稱的文件讀取數(shù)據(jù)
public FileInputStream(String name) throws FileNotFoundException
3.創(chuàng)建一個(gè)輸入文件流捺宗,從指定的文件描述器讀取數(shù)據(jù)
public FileInputStream(FileDescriptor fdObj)
InputStream的其他子類
1.ObjectInputStream(對象輸入流)
2.ByteArrayInputStream(字節(jié)數(shù)組輸入流)
把內(nèi)存的一個(gè)緩沖區(qū)作為InputStream使用。
構(gòu)造方法有:
(1)創(chuàng)建一個(gè)字節(jié)數(shù)組輸入流屁擅,使用buf作為它的緩沖區(qū)數(shù)組偿凭,從緩沖區(qū)數(shù)組中讀取數(shù)據(jù)
public ByteArrayInputStream(byte buf[])
(2)創(chuàng)建一個(gè)字節(jié)數(shù)組輸入流,從指定字節(jié)數(shù)組中讀取數(shù)據(jù)
public ByteArrayInputStream(byte buf[], int offset, int length)
//offset表示讀取緩沖區(qū)中第一個(gè)字節(jié)的偏移
//length表示從緩沖區(qū)讀取的最大字符數(shù)
3.PipedInputStream(管道輸入流)
管道輸入流是一個(gè)通訊管道的接收端派歌。
構(gòu)造方法有:
(1)創(chuàng)建連接到指定管道輸出流的管道輸入流
public PipedInputStream(PipedOutputStream src) throws IOException
public PipedInputStream(PipedOutputStream src, int pipeSize)
throws IOException
//使用指定的管道大小作為管道的緩沖
(2)創(chuàng)建一個(gè)管道輸入流弯囊,該輸出流尚未連接到管道輸出流
public PipedInputStream()
public PipedInputStream(int pipeSize)
//使用指定的管道大小
4.SequenceInputStream(序列輸入流)
此類允許應(yīng)用程序把幾個(gè)輸入連續(xù)地合并起來痰哨,它從一個(gè)有序的輸入流集合開始,每個(gè)輸入流依次被讀取到文件的末尾匾嘱,直到到達(dá)最后一個(gè)輸入流的文件末尾斤斧。
構(gòu)造方法有:
(1)參數(shù)中枚舉生成運(yùn)行時(shí)類型為輸入流的對象。新創(chuàng)建一個(gè)序列輸入流霎烙,通過讀取由枚舉產(chǎn)生的輸入流來初始化它撬讽。
public SequenceInputStream(Enumeration<? extends InputStream> e)
(2)新創(chuàng)建一個(gè)序列輸入流,按參數(shù)順序讀取輸入流s1,s2來初始化它悬垃。
public SequenceInputStream(InputStream s1, InputStream s2)
5.StringBufferInputStream
不推薦使用游昼,此類不能將字符正確地轉(zhuǎn)換為字節(jié)。從一個(gè)串創(chuàng)建一個(gè)流的最佳方法是采用StringReader類尝蠕。
6.FilterInputStream
其子類有LineNumberInputStream(java8中已不建議使用)烘豌、DataInputStream、BufferedInputStream看彼、PushbackInputStream廊佩。
代碼示例:解序列化
讀取文件test1.txt內(nèi)容的代碼示例:
public class Test {
public static void main(String[] args) {
try {
File f = new File("E:/test1.txt");
//如果文件不存在,就會拋出異常
FileInputStream fs = new FileInputStream(f);
byte[] b = new byte[(int) f.length()];
//文件中內(nèi)容都讀到此數(shù)組中靖榕,數(shù)組大小由文件決定
//在不知道輸入文件大小時(shí)标锄,可用while循環(huán)
int temp = 0;
int len = 0;
while ((temp = fs.read()) != -1) {
//-1為文件讀完的標(biāo)志
b[len] = (byte) temp;
len++;
}
//可以直接fs.read(b);讀取內(nèi)容
//也可以一個(gè)一個(gè)讀取:for(int i=0;i<b.length;i++){b[i]=(byte)fs.read()};
fs.close();
//關(guān)閉輸出流
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
把序列化對象從文件中讀取出來茁计,會用到字節(jié)輸入流(與上文把序列化對象寫入文件關(guān)聯(lián)):
/**
* 把序列化對象從文件test.ser中讀取出來
* 讀取的時(shí)候料皇,讀取順序一定要與寫入順序相同
*/
public class Test {
public static void main(String[] args) {
try {
FileInputStream fs = new FileInputStream("E:/test.ser");
//如果文件不存在,會拋出異常
ObjectInputStream os = new ObjectInputStream(fs);
//ObjectOutputStream知道如何提取對象簸淀,但是要靠鏈接的stream提供文件存取
User a1 = (User) os.readObject();
//readObject()的返回類型是Object瓶蝴,要轉(zhuǎn)換為原來的User類型
System.out.println("user的內(nèi)容為");
System.out.println(a1.getId());
System.out.println(a1.getName());
List a2 = (List) os.readObject();
//讀取順序與讀入順序一致
System.out.println("list的內(nèi)容為");
System.out.println(a2);
os.close();
//關(guān)閉ObjectOutputStream毒返,F(xiàn)ileInputStream會自動跟著關(guān)閉
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
}
如下圖所示:
字符流
字符流處理的基本單元為2個(gè)字節(jié)的Unicode字符租幕,操作字符、字符數(shù)組或字符串拧簸,它通常用來處理文本數(shù)據(jù)劲绪。
java提供了Writer、Reader兩個(gè)專門操作字符流的類盆赤。表示以Unicode字符為單位往stream中寫入或讀取信息贾富。
字符輸出流Writer
類與方法定義
抽象類,定義如下:
public abstract class Writer implements Appendable, Closeable, Flushable
常用方法有:
1.寫一個(gè)字符
public void write(int c) throws IOException
2.寫一個(gè)字符數(shù)組
public void write(char cbuf[]) throws IOException
abstract public void write(char cbuf[], int off, int len) throws IOException;
//從cbuf[]的off位置開始牺六,寫入字符數(shù)為len的字符數(shù)組
3.寫入一個(gè)字符串
public void write(String str) throws IOException
public void write(String str, int off, int len) throws IOException
//從字符串str的off位置開始颤枪,寫入的字符數(shù)為len
4.將指定的字符序列caq追加到該writer
public Writer append(CharSequence csq) throws IOException
//追加從指定序列的start位置開始,至end位置的字符序列
public Writer append(CharSequence csq, int start, int end) throws IOException
5.將指定字符追加到該writer
public Writer append(char c) throws IOException
6.強(qiáng)制性清空緩存
abstract public void flush() throws IOException;
7.關(guān)閉輸出流
abstract public void close() throws IOException;
要想使用此類淑际,必須通過子類實(shí)例化對象畏纲,使用子類扇住。
繼承Writer的子類
FileWriter
如果是向文件中寫入內(nèi)容,應(yīng)該使用FileWriter子類盗胀。與FileOutputStream對應(yīng)艘蹋。
++FileWriter繼承自O(shè)utputStreamWriter,OutputStreamWriter繼承自Writer++
構(gòu)造方法:
1.構(gòu)造給定File對象的FileWriter(文件寫入器對象)
public FileWriter(File file) throws IOException
//如果apped設(shè)為true票灰,數(shù)據(jù)將寫到文件的末尾而不是開始
public FileWriter(File file, boolean append) throws IOException
2.構(gòu)造給定文件名的FileWriter
public FileWriter(String fileName) throws IOException
//如果append設(shè)為true女阀,數(shù)據(jù)將寫到文件的末尾
public FileWriter(String fileName, boolean append) throws IOException
3.構(gòu)造與文件描述器相關(guān)聯(lián)的FileWriter
public FileWriter(FileDescriptor fd)
Writer的其他子類
1.BufferedWriter
2.CharArrayWriter
與ByteArrayOutputStream對應(yīng)
3.PipedWriter
與PipedOutputStream對應(yīng)
4.FilterWriter
5.StringWriter
代碼示例:將字符串寫入文本文件
public class Test {
public static void main(String[] args) {
try {
FileWriter fw = new FileWriter("E:/test2.txt");
//文件如果不存在就會被創(chuàng)建
//如果是在文件中追加內(nèi)容,構(gòu)造方法中append的值設(shè)為true
BufferedWriter bw = new BufferedWriter(fw);
bw.write("Hello,World");
//這里以字符作參數(shù)
bw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
字符輸入流Reader
類與方法定義
抽象類屑迂,定義如下:
public abstract class Reader implements Readable, Closeable
常用方法有:
1.讀取單個(gè)字符
public int read() throws IOException
2.將內(nèi)容讀入字符數(shù)組浸策,返回讀入的長度,如果到達(dá)輸入流末端惹盼,返回-1
public int read(char cbuf[]) throws IOException
//len表示要讀取的最大字符數(shù)
//將輸入流中l(wèi)en個(gè)字符數(shù)據(jù)讀入一個(gè)字符數(shù)組中的榛,從數(shù)組的off位置開始存放len長度的數(shù)據(jù)
abstract public int read(char cbuf[], int off, int len) throws IOException;
3.關(guān)閉輸入流,并釋放與之關(guān)聯(lián)的任何系統(tǒng)資源
abstract public void close() throws IOException;
要想使用此類逻锐,必須通過子類實(shí)例化對象夫晌,使用子類。
繼承Reader的子類
FileReader
如果要從文件中讀取內(nèi)容昧诱,可以直接使用FileReader子類晓淀。FileReader與FileInputStream對應(yīng)。
++FileReader繼承自InputStreamReader盏档,InputStreamReader繼承自Reader++凶掰。
構(gòu)造方法:
1.創(chuàng)建一個(gè)新的FileReader,從指定的File對象讀取數(shù)據(jù)
public FileReader(File file) throws FileNotFoundException
2.創(chuàng)建一個(gè)新的FileReader蜈亩,從指定名稱的文件中讀取數(shù)據(jù)
public FileReader(String fileName) throws FileNotFoundException
3.創(chuàng)建一個(gè)新的FileReader懦窘,從指定的文件描述器讀取數(shù)據(jù)
public FileReader(FileDescriptor fd)
Reader的其他子類
1.BufferedReader
2.CharArrayReader
與ByteArrayInputStream對應(yīng)。此類實(shí)現(xiàn)一個(gè)可用作字符輸入流的字符緩沖區(qū)稚配。子類有LineNumberReader
3.PipedReader
與PipedInputStream對應(yīng)
4.FilterReader
子類有PushbackReader畅涂。
5.StringReader
代碼示例:
public class Test {
public static void main(String[] args) {
try {
FileReader fw = new FileReader("E:/test2.txt");
BufferedReader bw = new BufferedReader(fw);
//它只會在緩沖區(qū)讀空的時(shí)候才會回頭去讀取
//以字符數(shù)組的形式讀取數(shù)據(jù)
char[] c = new char[1024];
//所有內(nèi)容都讀到此數(shù)組中
int len = bw.read(c);
//read(char c[])返回讀入長度
bw.close();
System.out.println(new String(c, 0, len));
//把字符數(shù)組變成字符串輸出
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
//還可以以while循環(huán)判斷是否讀到底
int len=0;
int temp=0;
char[] c = new char[1024];
while((temp=bw.read())!=-1){
c[len]=(char)temp;
len++;
}
bw.close();
System.out.println(new String(c, 0, len));
//把字符數(shù)組變成字符串輸出
//還可以用readLine()方法
//直接用String變量來承接所讀取結(jié)果
String line=null;
while((line=bw.readLine())!=null){
System.out.println(line);
}
字節(jié)—字符轉(zhuǎn)換
OutputStreamWriter和InputStreamReader是字節(jié)流與字符流的轉(zhuǎn)換類。從源碼中分析:
++OutputStreamWriter是Writer的子類道川,將輸出的字符流轉(zhuǎn)換成字節(jié)流午衰。++
++InputStreamReader是Reader的子類,將輸入的字節(jié)流轉(zhuǎn)換成字符流冒萄。++
OutputStreamWriter
public class OutputStreamWriter extends Writer
OutputStreamWriter類是從字符流到字節(jié)流的橋梁臊岸。在OutputStreamWriter類中需要一個(gè)字節(jié)流的對象(OutputStream out)。
OutputStreamWriter將多個(gè)字符寫入到一個(gè)輸出流尊流,根據(jù)指定的字符編碼將寫入的字符編碼成字節(jié)帅戒。實(shí)際負(fù)責(zé)編碼的是StreamEncoder類,過程中必須使用指定的編碼集崖技。
構(gòu)造方法:
1.可以通過名稱指定支持的字符編碼集:
public OutputStreamWriter(OutputStream out, String charsetName)
throws UnsupportedEncodingException
2.構(gòu)造器中指定Charset類型:
public OutputStreamWriter(OutputStream out, Charset cs)
3.也可以接受平臺的默認(rèn)編碼集:
public OutputStreamWriter(OutputStream out)
4.可以使用指定charset encoder:
public OutputStreamWriter(OutputStream out, CharsetEncoder enc)
write()方法的每次調(diào)用都會在給定字符(或字符串)上調(diào)用編碼轉(zhuǎn)換器逻住。在寫入底層輸出流之前施流,將在緩沖區(qū)中積累產(chǎn)生的字節(jié)。
注意鄙信,傳遞給write()方法的字符沒有緩沖瞪醋。OutputStreamWriter的write()方法寫入的是字符(或字符串),而非字節(jié)装诡。寫入字節(jié)的是輸出字節(jié)流(OutputStream)银受。
為了提高效率,可以考慮將OutputStreamWriter包裝在一個(gè)BufferedWriter中鸦采,以避免頻繁的轉(zhuǎn)換宾巍。例如:
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
InputStreamReader
public class InputStreamReader extends Reader
InputStreamReader類是從字節(jié)流到字符流的橋梁。在InputStreamReader類中需要一個(gè)字節(jié)流的對象(InputStream in)渔伯。
它使用的字符集可以通過名稱指定顶霞,也可以明確Charset類型,也可接受平臺的默認(rèn)字符集锣吼。與OutputStreamWriter類似选浑。
構(gòu)造函數(shù):
public InputStreamReader(InputStream in, String charsetName)
public InputStreamReader(InputStream in, Charset cs)
public InputStreamReader(InputStream in)
每次調(diào)用InputStreamReader的read()方法,都可能導(dǎo)致從底層字節(jié)輸入流中讀取一個(gè)或多個(gè)字節(jié)玄叠。為了能有效地將字節(jié)轉(zhuǎn)化為字符古徒,可從底層輸入流中讀取更多字節(jié),而不只是滿足當(dāng)前讀取操作所需的字節(jié)读恃。
注意隧膘,InputStreamReader是Reader的子類,其read()方法讀取的是一個(gè)或多個(gè)字符寺惫。讀取字節(jié)的是字節(jié)輸入流(InputStream)疹吃。
為了提高效率,可以考慮將InputStreamReader包裝在一個(gè)BufferedReader中西雀,比如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
代碼示例:用Buffered從Socket上讀取數(shù)據(jù)
/**
*從Socket上讀取數(shù)據(jù)
*/
public class Test {
public static void main(String[] args) {
try {
Socket chatSocket = new Socket("127.0.0.1", 5000);
//建立對服務(wù)器的Socket連接
InputStreamReader stream = new InputStreamReader(chatSocket.getInputStream());
//從Socket取得輸入串流
//建立連接到Socket上的輸入串流InputStreamReader(轉(zhuǎn)換字節(jié)成字符的橋梁)
BufferedReader reader = new BufferedReader(stream);
String message = reader.readLine();
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
如下圖所示:
字節(jié)流與字符流的比較
字節(jié)流操作的基本單元是字節(jié)萨驶;字符流操作的基本單元為Unicode碼元。
字節(jié)流在操作的時(shí)候本身不會用到緩沖區(qū)的蒋搜,是與文件本身直接操作的篡撵;而字符流在操作的時(shí)候使用到緩沖區(qū)的判莉。
所有文件的存儲都是字節(jié)(byte)的存儲豆挽,在磁盤上保留的是字節(jié)。
- 在使用字節(jié)流操作中券盅,即使沒有關(guān)閉資源(close方法)帮哈,也能輸出;而字符流不使用clode方法的話锰镀,不會輸出任何內(nèi)容娘侍。
說明字符流用到了緩沖區(qū)咖刃,如果執(zhí)行關(guān)閉輸出流的話會刷新緩沖區(qū),所以可以把內(nèi)容輸出憾筏。如果沒有關(guān)閉嚎杨,可以調(diào)用flush()方法強(qiáng)制刷新緩沖區(qū),這樣可以在不使用close()的情況下輸出內(nèi)容氧腰。
輸入流枫浙、輸出流相關(guān)類的使用判斷
根據(jù)使用場景決定使用哪個(gè)類。參考[字符流和字節(jié)流的區(qū)別古拴,使用場景箩帚,相關(guān)類]。如下(不考慮特殊需要):
1.考慮最原始的數(shù)據(jù)格式是什么:
(1)二進(jìn)制格式(只要不能確定是純文本的):InputStream,OutputStream及其子類(字節(jié)流)黄痪。
(2)純文本格式(含純英文與漢字或其他編碼方式):Reader,Writer及其子類(字符流)紧帕。
2.是輸入還是輸出:
(1)輸入:Reader,InputStream類型的子類。
(2)輸出:Writer,OutputStream類型的子類桅打。
3.是否需要轉(zhuǎn)換流:
字節(jié)到字符:InputStreamReader
字符到字節(jié):OutputStreamWriter
4.數(shù)據(jù)來源(去向)是什么:
(1)是文件:FileInputStream,FileOutputStream ; FileReader,FileWriter
(2)是byte[]: ByteArrayInputStream, ByteArrayOutputStream
(3)是Char[]:CharArrayReader,CharArrayWriter
(4)是String:StringBufferInputStream,StringBufferOutputStream;StringReader,StringWriter
(5)是網(wǎng)絡(luò)數(shù)據(jù)流:InputStream,OutputStream;Reader,Writer
5.是否要緩沖:(要注意readLine()是否有定義是嗜,有什么比read(),writer()更特殊的輸入或輸出方法)
要緩沖:BufferedInputStream, BufferedOutputStream; BufferedReader, BufferedWriter
6.是否要格式化輸出:
要格式化輸出:PrintStream, PrintWriter
PrintStream是FilterOutputStream的子類挺尾。
PrintWriter是Writer的子類叠纷。可用PrintWriter寫數(shù)據(jù)到Socket上潦嘶。
還有如下特殊需要的情景:
(1)對象輸入輸出:ObjectInputStream, ObjectOutputStream
(2)進(jìn)程間通信:PipedInputStream, PipedOutputStream, PipedReader, PipedWriter
(3)合并輸入: SequenceInputStream
(4)更特殊的需要:
PushbackInputStream(FilterInputStream的子類)涩嚣,LineNumberInputStream(FilterInputStream的子類,java8中已不建議使用);
LineNumberReader(BufferedReader的子類)掂僵,PushbackReader(FilterReader的子類)