I/O流笔记

I/O流笔记

参考博文:字节流(强推,逻辑清晰,案例生动)

目录

  1. 基本字节流与字符流
  2. 缓冲流
  3. 转换流
  4. 数据流
  5. 序列化
  6. I/O重定向导图

1. 基本字节流与字符流

首先来看输入流(读),不论是字节还是字符,最关键的就是3个read()函数。他们的基本作用都是从目标文件中读东西,只不过读的方式有些不同。先看一下字节流:
int read()一次读取一个字节,返回值为int,返回的就是读到的那个字节(ASCⅡ码)。如果读到结尾,会返回 -1。

int read(byte b[])一次读取b.length个字节放到b数组中,返回的就是实际读到的字节数。 也就是说,正常情况下,返回值就是b数组的长度,但如果内容不足以放满b数组,就会返回实际的读取长度。读到结尾的时候也会返回-1。

int read(byte b[], int off, int len)一次读取len个字节放到b数组中,返回的int是实际读到的字节数,即正常情况是len,如果内容不够len,返回的就是实际的长度。但它不是从0开始放,而是从下标为off的位置开始放的。读到结尾的时候也是会返回 -1。

字符流的输入和字节流类似,只不过从读字节变成了读字符,返回值也依然是int。

在这里插入图片描述


接着是输出流,最关键的就是write()函数,他们的基本作用都是把流中的东西写到目标文件中去。还是先看字节流:
void write(int c)写入一个int数据。

void write(byte buff[])把buff数组中所有字节写入

void write(byte buff[], int off, int len)把buff数组中下标区间为[off,off+ len-1]的所有字节写入。(也就是从下标off开始写,一共写len个)

接着是字符流:
void write(String str)把buff数组中所有字节写入

void write(String str, int off, int len)把str字符串中从off位置开始,长度为len的字符串写入。

2. 缓冲流

参考博文:https://www.cnblogs.com/zxfei/p/10873898.html
首先要明确一个概念:对文件或其他目标频繁的读写操作,效率低,性能差。
使用缓冲流的好处是,能够高效的读写信息,原理是将数据先缓冲起来,然后一起写入或者读取出来。
字节流和字符流都是有缓冲流的,我们平常比较关注的是字符流的缓冲流,因为其不仅提供了缓冲区,还新增了独有方法readLine() ,使得读取更加高效。
FileReader:内部使用InputStreamReader,解码过程,byte->char,默认缓存大小是8k
BufferedReader:默认缓存大小是8k,但是可以手动指定大小,把数据直接读取到缓存中,减少转换过程的次数,效率更高。所以虽然FileReader中已经加入了缓存,仍要加上BufferedReader的原因

3. 转换流

我们一般在一下两种情况下会使用转换流

  1. 源或者目的对应的设备是字节流,但操作的是文本数据,可以用转换流来做桥梁。

  2. 一旦操作文本需要具体的指定编码表时,必须使用用转换流。

InputStreamReader和OutputStreamWriter,从命名上看,可以明显知道他们是Reader和Writer的子类。作用就是把字节流和字符流相互转换,其中InputStreamReader是把字节转字符,OutputStreamWriter是把字符转字节。构造方法如下:
InputStreamReader 会将传入的字节流变为字符流

InputStreamReader isr = new InputStreamReader(InputStream in);//构造一个默认编码集的InputStreamReader类

InputStreamReader 会把字符流转到传入的字节流中,这样就可以使用字符流的特有方法去写字节流(也就是我虽然用的字符流的方法,但我实际上是字节流写入的)。

OutputStreamWriter osw = new OutputStreamWriter(OutputStream out);//构造一个默认编码集的OutputStreamWriter类

那么针对第二种情况——需要转换编码,我们如何来使用转换流呢?
比如说我们有一个utf-8编码格式的文件,我想要读取他,就可以使用

new InputStreamReader(new FileInputStream("a.txt"), "utf-8"));

来指定我们的字节流,要使用什么样的编码,把文件转换为字符流。

同样,输出的时候,可以使用

 new OutputStreamWriter(new FileOutputStream("b.txt"), "gbk"));

来指定我们在写入的时候,用什么编码方式来解析字节,从而输出到文件中。

这个过程是这样的:我们读a文件,首先读取的还是它的字节,然后因为我们指定了"UTF-8",所以会把字节按照此规则转换为字符,然后被我们读出来。读出来字符以后,再使用字符输出流(在这里也就是OutputStreamWriter),然后把字符按照设定的编码——gbk,重新编码,再输出到b文件中,这样b文件中就是使用gbk编码的了。
在这里插入图片描述

4. 数据流

DataInputStream/DataOutputStream
普通的字节流都是以字节为单位进行读写。那么如果想以其他的基本数据类型,比如int,double。就可以使用数据流。
DataOutputStream
DataOutputStream是装饰类基类FilterOutputStream的子类,FilterOutputStream是OutputStream的子类,它的构造方法是:

public FilterOutputStream(OutputStream out)

DataOutputStream可以以各种基本类型和字符串写入数据,部分方法如下:

void writeBoolean(boolean v) throws IOException;
void writeInt(int v) throws IOException;
void writeDouble(double v) throws IOException;
void writeUTF(String s) throws IOException;

在写入时,DataOutputStream会将这些类型的数据转换为其对应的二进制字节,比如:

writeBoolean: 写入一个字节,如果值为true,则写入1,否则0
writeInt: 写入四个字节,最高位字节先写入,最低位最后写入
writeUTF: 将字符串的UTF-8编码字节写入,这个编码格式与标准的UTF-8编码略有不同,不过,我们不用关心这个细节。
与FilterOutputStream一样,DataOutputStream的构造方法也是接受一个已有的OutputStream:

public DataOutputStream(OutputStream out)

5. 序列化流

为了把对象当作整体保存到文件中,I/O流提供了对象流来处理这类问题(当然,只有实现了序列化接口的类的对象才能被序列化)。
他们分别是:
ObjectOutputStream和ObjectInputStream,它们可以包装一个其它类型的流,比如:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("path"));

写入对象就调用writeObject(),如

oos.writeObject(stu);//stu是一个学生类对象

如果想要一次写入多个对象,可以把对象放入集合中,然后使用:

oos.writeObject(list);

来达到目的。
读对象的话,使用readObject(),如

Student stu = (Student)oos.readObject();

读对象集合的话:

ArrayList<Student> stus = (ArrayList<Student>)oos.readObject();

6. I/O重定向

System.in和System.out是Java提供了两个标准输入/输出流,主要用于从键盘接收数据和向屏幕输出数据。
System.in也有int read()和int read(byte b[])两个方法,用法和基本流类似。
System.out则有我们十分熟悉的两个方法——print()和println()。
为了重定向标准I/O流(即让键入和输出不局限与控制台,而到其他我们想要的地方),提供了3个方法:

static void setIn(InputStream in)----重定向标准输入流
static void setOut(PrintStream out)----重定向标准输出流
static void setErr(PrintStream err)----重定向标准错误与输出流

下面的代码作用是:内容不再输出到控制台,而是到指定的文件中。

//创建PrintStream输出流
PrintStream ps = new PrintStream(new FileOutoutStream("hello.txt"));
System.setOut(ps);
//向hello文件中输出内容
System.out.print("Hello World !");
System.out.println(new ReOut());

字节流和字符流

字符流的本质上,其实依然是字节流:这里不做详细比较。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值