转化流和IO流操作规律

一、转换流

1.概述

在IO包中实际上分为字节流和字符流,但是除了这两个流之外,还存在一组字节流-字符流的转换类。

①. OutputStreamWriter:是Writer的子类,将输出的字符流变成字节流,即将一个字符流的输出对象变为字节流输出对象。

②. InputStreamReader:是Reader的子类,将输入的字节流变成字符流,即将一个字节流的输入对象变成字符流的输入对象。

如果以文件操作为例,则内存中的字符数据需要通过OutputStreamWriter变成字节流才能保存在文件中,读取时需要将输入的字节流通过InputStreamReader变成字符流,转化步骤如图:


从图中可以清晰地发现,不管如何操作,最终全部是以字节的形式保存在文件中。

2.OutputStreamWriter和InputStreamReader的构造方法以及常用方法

OutputStreamWriter的构造方法:

// 创建使用默认字符编码的 OutputStreamWrite,默认编码表GBK
public OutputStreamWriter(OutputStream out)
// 创建使用指定字符集的 OutputStreamWriter。
public OutputStreamWriter(OutputStream out, String charsetName) throws UnsupportedEncodingException
OutputStreamWriter的方法:

// 刷新该流的缓冲。
public void flush() throws IOException
// 关闭此流,但要先刷新它。实际上它调用了父类Writer的close()方法
public void close() throws IOException
// 写入字符数组的某一部分
public void write(char[] cbuf, int off, int len) throws IOException
InputStreamReader的构造方法:

// 创建一个使用默认字符集的 InputStreamReader
public InputStreamReader(InputStream in)
// 创建使用指定字符集的 InputStreamReader
public InputStreamReader(InputStream in, String charsetName) throws UnsupportedEncodingException
InputStreamReader的方法:

// 关闭该流并释放与之关联的所有资源,和OutputStreamWriter一样,调用了Reader类的close()方法
public void close() throws IOException
// 将字符读入数组中的某一部分。 
public int read(char[] cbuf, int offset, int length) throws IOException

3.转化流示例

示例一:将字节输出流变成字符输出流
Writer out = new OutputStreamWrite(new FileOutputStream(new File("..."))); // 字节流变为字符流
示例二:将字节输入流变成字符输入流

Reader in = new InputStreamReader(new FileInputStream(new File("...")));
范例:从键盘读取数据,转化大写,显示在屏幕上。

BufferedReader reader = new BufferedReader(new InputStreamReader(
				System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
		System.out));
String line = null;
while ((line = reader.readLine()) != null) {
	if ("over".equals(line))
		break;
	writer.write(line.toUpperCase());
	writer.newLine();
	writer.flush();
}
// 因为是从System获取的流可以不关闭,随着系统的结束而结束
writer.close();
reader.close();

二、IO流的操作规律

1. 明确数据源和目的

源:输入流  InputStream、Reader  一定是被读取的。

目的:输出流  OutputStream、 Writer  一定是被写入的。

2. 操作的数据是否为纯文本的数据?

纯文本:字符流  Reader、 Writer

非纯文本: 字节流 InputStream、OutputStream

如果是源并且是纯文本,Reader

如果是目的并且是纯文本,Writer

3. 当明确体系后,在明确要是使用那个具体的对象

①. 通过设备来区分:

源设备:键盘(System.in)、硬盘(FileReader、FileInputStream)、内存(ByteArrayInputStream ...)、网络(Socket)。

目的设备:显示器(控制台System.out)、硬盘(FileWriter、FileOutputStream)、内存(ByteArrayOutputStream ...)、网络(Socket)。

②.明确是否需要额外功能?

Ⅰ. 是否需要高效?缓冲区BufferedXXX

Ⅱ. 是否需要转化?转化流 InputStreamReader、OutputStreamWriter

Ⅲ. 是否操作基本数据类型?DataInputStream、DataOutputStream

Ⅳ. 是否操作对象?ObjectInputStream、ObjectOutputStream

Ⅴ. 需要对多个源合并吗?SequenceInputStream

Ⅵ. 需要保存数据的表现形式到目的地吗?PrintWriter

范例1: 复制一个文本文件。

根据以上的操作规律,明确需要什么对象。

Ⅰ. 明确源和目的:源(InputStream、 Reader)、目的(OutputStream、Writer)

Ⅱ. 明确是否为纯文本?是。源(Reader)、目的(Writer)

Ⅲ. 明确具体设备:源(硬盘)、目的(硬盘)

源对应的体系Reader中可以操作硬盘设备的对象是 FileReader 
目的对应的体系Writer中可以操作硬盘设备的对象是FileWriter

Ⅳ. 需要额外功能码?需要高效,使用缓冲区

示例代码

// 源
BufferedReader bufferedReader = new BufferedReader(new FileReader("source.txt"));
// 目的
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("target.txt"));
// 读写操作
String line = null;
while ((line = bufferedReader.readLine()) != null) {
	bufferedWriter.write(line);
	bufferedWriter.newLine(); 
	bufferedWriter.flush();
}
// 关闭资源
bufferedWriter.close();
bufferedReader.close();
范例2:复制一个图片

Ⅰ. 明确源和目的:源(InputStream、 Reader)、目的(OutputStream、Writer)

Ⅱ. 明确是否为纯文本?否。源(InputStream)、目的(OutputStream)

Ⅲ. 明确具体设备:源(硬盘)、目的(硬盘)

源对应的体系InputStream中可以操作硬盘设备的对象是 FileInputStream
目的对应的体系OutputStream中可以操作硬盘设备的对象是FileOutputStream

示例代码

FileInputStream fileInputStream = new FileInputStream("source.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("target.jpg");
int len;
byte[] bytes = new byte[1024];
while ((len = fileInputStream.read(bytes)) != -1) {
	fileOutputStream.write(bytes, 0, len);
}
fileOutputStream.close();
fileInputStream.close();
范例3: 读取键盘录入,存储到一个文件中。

Ⅰ. 明确源和目的:源(InputStream、 Reader)、目的(OutputStream、Writer)

Ⅱ. 明确是否为纯文本?是。源(Reader)、目的(Writer)

Ⅲ. 明确具体设备:源(键盘)、目的(硬盘)

具体对象:源(System.in)、目的(FileWriter)

Ⅳ. 需要额外功能码?需要高效,使用缓冲区; 需要转化流

实例代码:

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("target.txt"));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
	if ("over".equals(line)) { 
		break;
	}
	bufferedWriter.write(line);
	bufferedWriter.newLine();
	bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
范例4:读取一个文本文件,将文件中文本按照指定的编码表UTF-8写入到另一个文件中。

Ⅰ. 明确源和目的:源(InputStream、 Reader)、目的(OutputStream、Writer)

Ⅱ. 明确是否为纯文本?是。源(Reader)、目的(Writer)

Ⅲ. 明确具体设备:源(硬盘(File))、目的(硬盘(File))

这样做不行,满足不了需求,为什么呢?
因为这个两个对象在操作文本数据,都是用了默认的编码表。本机中默认码表是GBK.
而需求中希望写入到文件的数据是按照utf-8的码表。

源对象不变。
FileReader fr = new FileReader("a.txt");
需要目的为指定编码表。
这时就要用到转换流。因为转换流中可以指定具体的编码表。 需要往里传递一个字节流,而且要操作文件,FileOutputStream
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("target.txt"),"UTF-8");

Ⅳ. 需要额外功能码?需要高效,使用缓冲区。










  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值