1 基本概括

2 主要介绍
2.1 InputStreamReader/OutputStreamWriter 相比FileReader和FileWriter的优势
前者可以指定读取和写出的编码,不容易出现乱码。
2.2 转换流的作用
1. 如果目前所 获取到的是一个字节流需要转换字符流使用,这时候就可以使用转换流。 字节流----> 字符流
2. 使用转换流可以指定编码表进行读写文件
2.3 编码与解码
1 经常说到编码和解码也就是从字符到字节,或者字节到字符的转换,转换的规则就是按照指定的码表
2 只要理解了码的含义 :指的是二进制的 0 1 的数值序列编码表中都有字符对应的数值序列编码把字符从符号转变成二进制序列就是编码解码就是转换为指定的字符形式。
3 字节流和字符流之间的转换,自然离不开编码与解码计算机最底层数据的存储是二进制序列,也就是字节所以如果是从最底层读取,那么就是涉及二进制到字符的解码从字符写入到最底层,就是字符的编码
2.4 StreamDecoder到底是什么
StreamDecoder继承了Reader,所以他是一个Reader另外他内部又包含了一个InputStream in;
这个in 通过他的forInputStreamReader系列方法,通过入参InputStream进行设置。
2.5 简单总结
1转换流作为适配器的应用,只需要理解目标和被适配角色即可
2 目标就是在外面抛头露面,直接接触使用的形式,被适配角色就是幕后默默奉献的,也就是他们提供了Reader和Writer字符形式的读写操作方式
3 而内部则都是使用被适配角色,字节流的形式进行读写,中间涉及到的编码与解码 则依靠StreamEncoder 和StreamDecoder
3 用例
3.1一个字节流中的字节解码成字符
@Test
public void IOTest1() throws Exception {InputStream in = new FileInputStream("D:/hello.txt");// 读取文件的数据,注意文件编码为UTF-8,防止读取乱码// 将输入的字节流 ------转换成----> 字符流InputStreamReader isr = new InputStreamReader(in);// 读取char[] data = new char[1024];int len = isr.read(data);//读取字符流中的数据,用char[]数组一次性接收System.err.println(new String(data, 0, len));isr.close();
}
3.2 写入的字符编码成字节后写入一个字节流
@Test
public void IOTest2() throws Exception { OutputStream out = System.err;// 打印到控制台,也可以输出到文件OutputStreamWriter osr = new OutputStreamWriter(out);//输出 往out里面准备写内容,内容在下面String str = "Hello World!";osr.write(str);//写//osr.flush();//如果用于网络传输,记得强制刷新缓冲区,否则输出的数据只停留在缓冲区中,而无法进行网络传输osr.close();//关闭资源
}
3.3 实现了从一个用UTF-8编码的源文件复制数据到一个用GBK编码的目标文件
private static void Utf8ToGbk() {BufferedReader br = null;BufferedWriter bw = null;try {br = new BufferedReader(new InputStreamReader(new FileInputStream("./test.txt"), "utf-8"));bw = new BufferedWriter(new FileWriter("./test/2.txt"));
// bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("./src/res/2.txt")));String str = null;while(null != (str = br.readLine())) {bw.write(str);bw.newLine();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != bw) {try {bw.close();} catch (IOException e) {e.printStackTrace();}}if(null != br) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}
}
3.4 实现了从一个用GBK编码的源文件复制数据到一个用UTF-8编码的目标文件
private static void gbkToUtf8() {BufferedReader br = null;BufferedWriter bw = null;try {br = new BufferedReader(new FileReader("./src/res/2.txt"));
// br = new BufferedReader(new InputStreamReader(new FileInputStream("./test.txt")));//使用默认字符集bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("./test2.txt"), "utf-8"));String str = null;while(null != (str = br.readLine())) {bw.write(str);bw.newLine();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != bw) {try {bw.close();} catch (IOException e) {e.printStackTrace();}}if(null != br) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}}
4 源码分析
4.1 InputStreamReader 源码
package java.io;import java.nio.charset.Charset;import java.nio.charset.CharsetDecoder;import sun.nio.cs.StreamDecoder;// 将“字节输入流”转换成“字符输入流”public class InputStreamReader extends Reader {private final StreamDecoder sd;// 根据in创建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 availablethrow new Error(e);}}// 根据in创建InputStreamReader,使用编码charsetName(编码名)public InputStreamReader(InputStream in, String charsetName)throws UnsupportedEncodingException{super(in);if (charsetName == null)throw new NullPointerException("charsetName");sd = StreamDecoder.forInputStreamReader(in, this, charsetName);}// 根据in创建InputStreamReader,使用编码cspublic InputStreamReader(InputStream in, Charset cs) {super(in);if (cs == null)throw new NullPointerException("charset");sd = StreamDecoder.forInputStreamReader(in, this, cs);}// 根据in创建InputStreamReader,使用解码器decpublic InputStreamReader(InputStream in, CharsetDecoder dec) {super(in);if (dec == null)throw new NullPointerException("charset decoder");sd = StreamDecoder.forInputStreamReader(in, this, dec);}// 获取解码器public String getEncoding() {return sd.getEncoding();}// 读取并返回一个字符public int read() throws IOException {return sd.read();}// 将InputStreamReader中的数据写入cbuf中,从cbuf的offset位置开始写入,写入长度是lengthpublic 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();}// 关闭InputStreamReaderpublic void close() throws IOException {sd.close();}}
4.2 OutputStreamWriter 源码
package java.io;import java.nio.charset.Charset;import java.nio.charset.CharsetEncoder;import sun.nio.cs.StreamEncoder;// 将“字节输出流”转换成“字符输出流”public class OutputStreamWriter extends Writer {private final StreamEncoder se;// 根据out创建OutputStreamWriter,使用编码charsetName(编码名)public OutputStreamWriter(OutputStream out, String charsetName)throws UnsupportedEncodingException{super(out);if (charsetName == null)throw new NullPointerException("charsetName");se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);}// 根据out创建OutputStreamWriter,使用默认的编码public OutputStreamWriter(OutputStream out) {super(out);try {se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);} catch (UnsupportedEncodingException e) {throw new Error(e);}}// 根据out创建OutputStreamWriter,使用编码cspublic OutputStreamWriter(OutputStream out, Charset cs) {super(out);if (cs == null)throw new NullPointerException("charset");se = StreamEncoder.forOutputStreamWriter(out, this, cs);}// 根据out创建OutputStreamWriter,使用编码器encpublic OutputStreamWriter(OutputStream out, CharsetEncoder enc) {super(out);if (enc == null)throw new NullPointerException("charset encoder");se = StreamEncoder.forOutputStreamWriter(out, this, enc);}java io系列01之 "目录"// 获取编码器encpublic String getEncoding() {return se.getEncoding();}// 刷新缓冲区void flushBuffer() throws IOException {se.flushBuffer();}// 将单个字符写入到OutputStreamWriter中public void write(int c) throws IOException {se.write(c);}// 将字符数组cbuf从off开始的数据写入到OutputStreamWriter中,写入长度是lenpublic void write(char cbuf[], int off, int len) throws IOException {se.write(cbuf, off, len);}// 将字符串str从off开始的数据写入到OutputStreamWriter中,写入长度是lenpublic void write(String str, int off, int len) throws IOException {se.write(str, off, len);}java io系列01之 "目录"// 刷新“输出流”// 它与flushBuffer()的区别是:flushBuffer()只会刷新缓冲,而flush()是刷新流,flush()包括了flushBuffer。public void flush() throws IOException {se.flush();}// 关闭“输出流”public void close() throws IOException {se.close();}}


















