字節(jié)流、字符流及其轉(zhuǎn)換龙巨、比較與使用場景

本文包含以下知識點(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為例)

  1. 使用File類打開一個(gè)文件瞳腌;
  2. 通過字節(jié)流或字符流的子類,指定輸出的位置镜雨;
  3. 進(jìn)行讀/寫操作嫂侍;
  4. 關(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的子類

images

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;
    }
}

如下圖所示

image

字節(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的子類

image

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();
        }
    }
}

如下圖所示:

image

字符流

字符流處理的基本單元為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的子類

image

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的子類

image

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();
        }
    }
}

如下圖所示:

image

字節(jié)流與字符流的比較

  1. 字節(jié)流操作的基本單元是字節(jié)萨驶;字符流操作的基本單元為Unicode碼元。

  2. 字節(jié)流在操作的時(shí)候本身不會用到緩沖區(qū)的蒋搜,是與文件本身直接操作的篡撵;而字符流在操作的時(shí)候使用到緩沖區(qū)的判莉。

所有文件的存儲都是字節(jié)(byte)的存儲豆挽,在磁盤上保留的是字節(jié)。

  1. 在使用字節(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的子類)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末航厚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子锰蓬,更是在濱河造成了極大的恐慌幔睬,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芹扭,死亡現(xiàn)場離奇詭異麻顶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)舱卡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門怨绣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翩活,“玉大人,你說我怎么就攤上這事∠舴停” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我赵辕,道長,這世上最難降的妖魔是什么概龄? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任还惠,我火速辦了婚禮,結(jié)果婚禮上私杜,老公的妹妹穿的比我還像新娘吸重。我一直安慰自己,他們只是感情好歪今,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布嚎幸。 她就那樣靜靜地躺著,像睡著了一般寄猩。 火紅的嫁衣襯著肌膚如雪嫉晶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天田篇,我揣著相機(jī)與錄音替废,去河邊找鬼。 笑死泊柬,一個(gè)胖子當(dāng)著我的面吹牛椎镣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兽赁,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼状答,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了刀崖?” 一聲冷哼從身側(cè)響起惊科,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎亮钦,沒想到半個(gè)月后馆截,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜂莉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年蜡娶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片映穗。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窖张,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出男公,到底是詐尸還是另有隱情荤堪,我是刑警寧澤合陵,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布枢赔,位于F島的核電站澄阳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏踏拜。R本人自食惡果不足惜碎赢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望速梗。 院中可真熱鬧肮塞,春花似錦、人聲如沸姻锁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽位隶。三九已至拷窜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涧黄,已是汗流浹背篮昧。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笋妥,地道東北人懊昨。 一個(gè)月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像春宣,于是被迫代替她去往敵國和親酵颁。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 在經(jīng)過一次沒有準(zhǔn)備的面試后月帝,發(fā)現(xiàn)自己雖然寫了兩年的android代碼材义,基礎(chǔ)知識卻忘的差不多了。這是程序員的大忌嫁赏,沒...
    猿來如癡閱讀 2,841評論 3 10
  • IO簡單概述 IO解決問題 : 解決設(shè)備與設(shè)備之間的數(shù)據(jù)傳輸問題(硬盤 -> 內(nèi)存 內(nèi)存 -> 硬盤) 讀和寫文...
    奮斗的老王閱讀 3,439評論 0 53
  • 一其掂、流的概念和作用。 流是一種有順序的潦蝇,有起點(diǎn)和終點(diǎn)的字節(jié)集合款熬,是對數(shù)據(jù)傳輸?shù)目偝苫虺橄蟆<磾?shù)據(jù)在兩設(shè)備之間的傳輸...
    布魯斯不吐絲閱讀 10,039評論 2 95
  • 日子就這樣走著 不驚不喜 不緩不急 有些不屑 有些無情 歡樂喜悅挑不起他的熱情 悲苦哀痛也換不來他的同情 他永遠(yuǎn)在...
    煙雨心清閱讀 388評論 8 9
  • 錯過你就會發(fā)現(xiàn)好后悔攘乒! 皖北門診部定于2017年10月10日——31日舉行大型免費(fèi)義診活動贤牛。 免費(fèi)義診范圍: ...
    AA老七閱讀 378評論 0 0