Java8 I/O源码-InputStreamReader与OutputStreamWriter

今天学习InputStreamReader与OutputStreamWriter。

InputStreamReader,字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。

OutputStreamWriter,字符流通向字节流的桥梁:它使用指定的charset将要写入流中的字符编码成字节。

InputStreamReader

每次调用InputStreamReader中的read方法都会导致从底层输入流读取一个或多个字节,然后调用编码转换器将字节转化为字符。为避免频繁调用转换器,实现从字节到字符的高效转换,可以提前从底层流读取更多的字节。

为了达到最高效率,可要考虑在BufferedReader内包装InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

public class InputStreamReader extends Reader {

    //InputStreamReader的功能是依赖StreamDecoder完成的。
    private final StreamDecoder sd;

    /**
     * 创建一个使用默认字符集的InputStreamReader。
     */
    public InputStreamReader(InputStream in) {
        super(in);
        try {
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
        } catch (UnsupportedEncodingException e) {
            // The default encoding should always be available
            throw new Error(e);
        }
    }

    /**
     * 创建使用指定字符集的 InputStreamReader。
     *
     * @exception  UnsupportedEncodingException 如果不支持指定的字符集
     */
    public InputStreamReader(InputStream in, String charsetName)
        throws UnsupportedEncodingException
    {
        super(in);
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
    }

    /**
     * 创建使用给定字符集的InputStreamReader。
     */
    public InputStreamReader(InputStream in, Charset cs) {
        super(in);
        if (cs == null)
            throw new NullPointerException("charset");
        sd = StreamDecoder.forInputStreamReader(in, this, cs);
    }

    /**
     * 创建使用给定字符集解码器的InputStreamReader。
     */
    public InputStreamReader(InputStream in, CharsetDecoder dec) {
        super(in);
        if (dec == null)
            throw new NullPointerException("charset decoder");
        sd = StreamDecoder.forInputStreamReader(in, this, dec);
    }

    /**
     * 返回此流使用的字符编码的名称。
     * 如果该编码有历史上用过的名称,则返回该名称;否则返回该编码的规范化名称。
     * 如果使用InputStreamReader(InputStream, String)构造方法创建此实例,
     * 则返回的由此编码生成的唯一名称可能与传递给该构造方法的名称不一样。
     * 如果流已经关闭,则此方法将会返回 null。
     * 
     * @return 此编码的历史名称,如果流已经关闭,则返回null
     */
    public String getEncoding() {
        return sd.getEncoding();
    }

    /**
     * 读取单个字符。
     */
    public int read() throws IOException {
        return sd.read();
    }

    /**
     * 将字符读入数组中的某一部分。
     */
    public int read(char cbuf[], int offset, int length) throws IOException {
        return sd.read(cbuf, offset, length);
    }

    /**
     * 判断此流是否已经准备好用于读取。
     * 如果其输入缓冲区不为空,或者可从底层字节流读取字节,则InputStreamReader已做好被读取准备。
     */
    public boolean ready() throws IOException {
        return sd.ready();
    }

    //关闭该流并释放与之关联的所有资源。
    public void close() throws IOException {
        sd.close();
    }
}
demo
/**
 * InputStreamReader demo
 * @author panww
 */
public class InputStreamReaderTest {

    /**
     * inputStreamReader.txt中的内容为“潘威威的博客http://blog.csdn.net/panweiwei1994”
     */
    @Test
    public void test() {
        try {
            File file = new File("inputStreamReader.txt");
            InputStreamReader reader = new InputStreamReader(new FileInputStream(file),"gbk");

            System.out.println("ready():"+reader.ready());

            System.out.println("getEncoding():"+reader.getEncoding());

            System.out.println("read():"+(char)reader.read());

            char[] buf = new char[40];
            reader.read(buf, 0, buf.length);
            System.out.println("read(char[], int, int):"+(new String(buf)));

            reader.close();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

控制台打印内容为

ready():true
getEncoding():GBK
read():潘
read(char[], int, int):威威的博客http://blog.csdn.net/panweiwei1994

OutputStreamWriter

每次调用write()方法都会导致在给定字符(或字符集)上调用编码转换器。为避免频繁调用转换器,在写入底层输出流之前,可以将得到的这些字节积累在缓冲区。例如,可考虑将OutputStreamWriter包装到BufferedWriter中。

Writer out = new BufferedWriter(new OutputStreamWriter(System.out));

此类总是使用字符集的默认替代序列替代错误代理元素和不可映射的字符序列。如果需要更多地控制编码过程,则应该使用CharsetEncoder 类。

public class OutputStreamWriter extends Writer {

    //OutputStreamWriter的功能是依赖于StreamEncoder完成的
    private final StreamEncoder se;

    /**
     * 创建使用默认字符编码的OutputStreamWriter。
     */
    public OutputStreamWriter(OutputStream out, String charsetName)
        throws UnsupportedEncodingException
    {
        super(out);
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
    }

    /**
     * 创建使用给定字符集的OutputStreamWriter。
     */
    public OutputStreamWriter(OutputStream out) {
        super(out);
        try {
            se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
        } catch (UnsupportedEncodingException e) {
            throw new Error(e);
        }
    }

    /**
     * 创建使用给定字符集的OutputStreamWriter。
     */
    public OutputStreamWriter(OutputStream out, Charset cs) {
        super(out);
        if (cs == null)
            throw new NullPointerException("charset");
        se = StreamEncoder.forOutputStreamWriter(out, this, cs);
    }

    /**
     * 创建使用给定字符集编码器的OutputStreamWriter。
     */
    public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
        super(out);
        if (enc == null)
            throw new NullPointerException("charset encoder");
        se = StreamEncoder.forOutputStreamWriter(out, this, enc);
    }

    /**
     * 返回此流使用的字符编码的名称。
     * 如果该编码具有历史名称,则返回该名称;否则返回该编码的规范化名称。
     * 如果此实例是用OutputStreamWriter(OutputStream, String)构造方法创建的,
     * 则返回的对于编码唯一的名称可能与传递给该构造方法的名称不同。
     * 如果流已经关闭,则此方法可能返回 null。
     */
    public String getEncoding() {
        return se.getEncoding();
    }

    /**
     * 刷新输出缓冲到底层字节流中,不刷新字节流。
     * 这个方法是非私有的,可以被PrintStream使用。
     */
    void flushBuffer() throws IOException {
        se.flushBuffer();
    }

    /**
     * 写入单个字符。
     */
    public void write(int c) throws IOException {
        se.write(c);
    }

    /**
     * 写入字符数组的某一部分。
     */
    public void write(char cbuf[], int off, int len) throws IOException {
        se.write(cbuf, off, len);
    }

    /**
     * 写入字符串的某一部分。
     */
    public void write(String str, int off, int len) throws IOException {
        se.write(str, off, len);
    }

    /**
     * 刷新该流的缓冲。
     */
    public void flush() throws IOException {
        se.flush();
    }

    //关闭此流。
    public void close() throws IOException {
        se.close();
    }
}
demo
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

import org.junit.Test;

/**
 * OutputStreamWriter Demo
 * 
 * @author panww
 */
public class OutputStreamWriterTest {

    @Test
    public void test() {
        try {
            File file = new File("inputStreamReader.txt");
            OutputStreamWriter out1 = new OutputStreamWriter(new FileOutputStream(file));
            out1.write("潘威威的博客");

            out1.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行后,inputStreamReader.txt中的内容为潘威威的博客

总结

  • InputStreamReader,字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。
  • 每次调用InputStreamReader中的read方法都会导致从底层输入流读取一个或多个字节,然后调用编码转换器将字节转化为字符。为避免频繁调用转换器,实现从字节到字符的高效转换,可以提前从底层流读取更多的字节。为了达到最高效率,可要考虑在BufferedReader内包装InputStreamReader。
  • InputStreamReader的功能是依赖于StreamDecoder完成的。
  • OutputStreamWriter,字符流通向字节流的桥梁:它使用指定的charset将要写入流中的字符编码成字节。
  • 每次调用write()方法都会导致在给定字符(或字符集)上调用编码转换器。为避免频繁调用转换器,在写入底层输出流之前,可以将得到的这些字节积累在缓冲区。例如,可考虑将OutputStreamWriter包装到BufferedWriter中。

关于InputStreamReader与OutputStreamWriter就讲到这里,想了解更多内容请参考

版权声明
作者:潘威威

原文地址:CSDN博客-潘威威的博客-http://blog.csdn.net/panweiwei1994/article/details/78398769

本文版权归作者所有,欢迎转载。转载时请在文章明显位置给出原文作者名字(潘威威)及原文链接。请勿将本文用于任何商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值