Java中IO流基本介绍(5)——InputStreamReader和OutputStreamWriter

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 available
    throw 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,使用编码cs
  public InputStreamReader(InputStream in, Charset cs) {
   super(in);
   if (cs == null)
    throw new NullPointerException("charset");
   sd = StreamDecoder.forInputStreamReader(in, this, cs);
  }
  // 根据in创建InputStreamReader,使用解码器dec
  public 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位置开始写入,写入长度是length
  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();
  }
  // 关闭InputStreamReader
  public 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,使用编码cs
  public OutputStreamWriter(OutputStream out, Charset cs) {
   super(out);
   if (cs == null)
    throw new NullPointerException("charset");
   se = StreamEncoder.forOutputStreamWriter(out, this, cs);
  }
  // 根据out创建OutputStreamWriter,使用编码器enc
  public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
   super(out);
   if (enc == null)
    throw new NullPointerException("charset encoder");
   se = StreamEncoder.forOutputStreamWriter(out, this, enc);
 }java io系列01之 "目录"
  // 获取编码器enc
  public 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中,写入长度是len
  public void write(char cbuf[], int off, int len) throws IOException {
   se.write(cbuf, off, len);
  }
  // 将字符串str从off开始的数据写入到OutputStreamWriter中,写入长度是len
  public 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();
  }
 }

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有鹿如溪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值