J07-Java IO流总结七 《 InputStreamReader和OutputStreamWriter 》
前面在介绍FileReader和FileWriter的时候有说到,FileReader的读取字符功能,以及FileWriter的写出字符的功能,都不是它们自己实现的,而是,它们分别继承了InputStreamReader和OuputStreamWriter这两个转换流,利用这两个转换流,实现了字节数据与字符数据之间的转换,关于这点可以通过FileReader和FileWriter的源码看出来。
下面将介绍这两个转换流,并分别通过几个简单的应用场景来熟悉它们的用法。
1. InputStreamReader
1.1 概念介绍
InputStreamReader将底层的字节数据转换为字符数据,可以显式的或者使用平台默认的字符集进行转换。所有的字符流的转换工作都依赖于它来完成。
根据API文档的描述,InputStreamReader 是字节流通向字符流的桥梁,它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:
BufferedReader in
= new BufferedReader(new InputStreamReader(System.in));
关于源码:
InputStreamReader的源码比较简单,它有一个非常重要的成员变量:
private final StreamDecoder sd;
InputStreamReader的主要实现都调用了这个流解码类StreamDecoder,它只有这一个成员变量,而这一个类把它的所有操作都包括了。StreamDecoder的主要作用是获取一个字节输入流InputStream,然后根据给定的编码方案读取字符,如果没有给定,则默认是系统编码。
由源码可知,InputStreamReader的设计使用到了装饰设计模式,它本身并没有提供啥功能,具体的实现其实都由StreamDecoder来实现了。
源码中关于InputStreamReader的几个构造方法需要格外注意一下,因为通过它的构造方法,可以显式的指定解码所需的字符集:

1.2 应用示例
System.in是字节流对象,代表键盘的输入,如果我们想按行接收用户的输入时,就必须用到缓冲字符流BufferedReader特有的方法readLine(),但是经过观察会发现在创建BufferedReader的构造方法的参数必须是一个Reader对象,如下:
public BufferedReader(Reader in)
这时候我们的转换流InputStreamReader就派上用场了。
示例代码如下所示:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; public class InputStreamReaderTest {
public static void main(String[] args) {
BufferedReader br = null; String str = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
while(!"exit".equals(str = br.readLine())) {
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码运行效果:

2. OutputStreamWriter
2.1 概念介绍
OutputStreamWriter是将字符数据转换为字节数据的流。可以显式的或者使用平台默认的字符集进行转换。所有的字符输出流的转换工作都依赖于它来完成。
根据API文档的描述,OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。
为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如:
Writer out
= new BufferedWriter(new OutputStreamWriter(System.out));
源码:
阅读OutputStreamWriter的源码,可以发现它跟InputStreamReader一样使用了装饰器模式,在它的类当中,持有了一个的引用StreamEncoder的应用,StreamEncoder可以理解为一个编码器,当调用OutputStreamWriter的write、close方法时,实际上底层调用的还是这个StreamEncoder的方法。
需要留意一下OutputStreamWriter的构造方法:

2.2 应用示例
System.out是字节流对象,代表输出到显示器,在上面的示例中按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用到字符流的write(String str)方法,所以我们要使用OutputStreamWriter将字符流转化为字节流。
示例代码如下所示:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter; public class ConvertStreamTest {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null; String str = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
bw = new BufferedWriter(new OutputStreamWriter(System.out)); while(!"bye".equals(str = br.readLine())) {
bw.write("-->" + str);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码运行效果:

3 转换流综合应用示例
下面的示例代码中定义了两个方法,分别为Utf8ToGbk()和gbkToUtf8(),其中,Utf8ToGbk()实现了从一个用UTF-8编码的源文件复制数据到一个用GBK编码的目标文件,gbkToUtf8()方法则正好反之。
示例代码:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException; public class ConvertTest {
public static void main(String[] args) {
// gbkToUtf8();
Utf8ToGbk(); } ////////////////////////////////////////////////////////////
private static void Utf8ToGbk() {
BufferedReader br = null;
BufferedWriter bw = null; try {
br = new BufferedReader(new InputStreamReader(new FileInputStream("./src/res/2_copy.txt"), "utf-8"));
bw = new BufferedWriter(new FileWriter("./src/res/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();
}
}
}
} ////////////////////////////////////////////////////////////
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("./src/res/2.txt")));//使用默认字符集 bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("./src/res/2_copy.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();
}
}
}
}
}
J07-Java IO流总结七 《 InputStreamReader和OutputStreamWriter 》的更多相关文章
- java io系列21之 InputStreamReader和OutputStreamWriter
InputStreamReader和OutputStreamWriter 是字节流通向字符流的桥梁:它使用指定的 charset 读写字节并将其解码为字符.InputStreamReader 的作用是 ...
- java IO流 (七) 对象流的使用
1.对象流: ObjectInputStream 和 ObjectOutputStream2.作用:ObjectOutputStream:内存中的对象--->存储中的文件.通过网络传输出去:序列 ...
- Java IO流学习
Java IO流学习 Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是 ...
- Java:IO流与文件基础
Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列的对象 ...
- java IO流详解
流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
- Java IO流学习总结
Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
- Java IO流
File类 ·java.io.File类:文件和目录路径名的抽象表示形式,与平台无关 ·File能新建.删除.重命名文件和目录,但File不能访问文件内容本身.如果需要访问文件内容本身,则需要使用输入 ...
- Java IO流题库
一. 填空题 Java IO流可以分为 节点流 和处理流两大类,其中前者处于IO操作的第一线,所有操作必须通过他们进行. 输入流的唯一目的是提供通往数据的通道,程序可以通过这个通道读取数 ...
- Java IO流总结
Java IO流分类以及主要使用方式如下: IO流 |--字节流 |--字节输入流 InputStream: int read();//一次读取一个字节 int read(byte[] bys);// ...
- Java IO流详尽解析
流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
随机推荐
- Centos记录所有用户登录和操作的详细日志
1.起因 最近Linux服务器上一些文件呗篡改,想追查已经查不到记录了,所以得想个办法记录下所有用户的操作记录. 一般大家通常会采用history来记录,但是history有个缺陷就是默认是1000行 ...
- 2018.06.30 BZOJ3083: 遥远的国度(换根树剖)
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 512 MB Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国 ...
- 2018.09.01 poj2689 Prime Distance(埃式筛法)
传送门 一道挺有趣的. 第一眼以为每个数都用miller_rabin判一次,但感觉会被卡时间啊. 继续分析发现可以晒出sqrt(r)中的所有素数,然后用类似埃式筛法的方法晒出[l,r]" r ...
- 用Java操作数据库Datetime数据
Date.Calendar.Timestamp的区别.相互转换与使用 1 Java.util.Date 包含年.月.日.时.分.秒信息. // String转换为Date String dateStr ...
- Linux服务器部署系列之三—DNS篇
网上介绍DNS的知识很多,在这里我就不再讲述DNS原理及做名词解释了.本篇我们将以一个实例为例来讲述DNS的配置,实验环境如下: 域名:guoxuemin.cn, 子域:shenzhen.guoxue ...
- day3之函数的初始及进阶
函数初始 函数的定义与调用 ''' def 函数名 (参数): 函数体 函数名:设定与变量相同 执行函数: 函数名() ''' 函数的返回值 # 函数返回值 return ''' 1.遇到return ...
- 移动 APP 网络优化概述
一般开发一个 APP,会直接调用系统提供的网络请求接口去服务端请求数据,再针对返回的数据进行一些处理,或者使用AFNetworking/OKHttp这样的网络库,管理好请求线程和队列,再自动做一些数据 ...
- openwrt,mjpeg流,wifi摄像头与APP联动,拍照、录像
最近公司好忙,自己主管的产品又忙着上线,好久都没更新博客了. 最近产品在做一款wifi摄像头,摄像头与手机同时连接在一个局域网内,即可实现摄像头图像在手机显示,并且拍照录像等功能 mjpeg是一张一张 ...
- cxgrid动态显示行号
uses cxLookAndFeelPainters; type TMyCxGrid = class(TObject) class procedure DrawIndicatorCell( ...
- Android 权限的由来
在Android APP开发过程中,某些行为动作需要在AndroidManifest.xml清单文件中进行权限相关的配置: <!-- 增加权限 --> <uses-permissio ...