Java数据传输的通道——IO流

一.概述

Java中的IO流是一种计算机用语,主要是用于处理数据的传输。IO流是数据传输所需的通道,用于实现数据在程序间的有序传输,可以提高数据传输效率和稳定性

也就是IO流用于读写文件中的数据

比如游戏的进度需要备份,这就是写。在下次登录游戏时数据还在,这就是读

IO流中以程序为参照物,程序向文件中读取数据,程序向文件中写入数据

⑴IO流的分类

①按照流的方向

IO流可以分为输入流和输出流

②按照操作的文件类型

IO流可以分为字节流和字符流

其中字节流可以操作所有类型的文件,如图片,视频

而字符流只能操作纯文本文件( Windows自带的记事本可以打开读懂的文件)

⑵IO流的作用

用于读写数据(本地文件,网络文件)

二.IO流体系结构

13d9dc77cbe94cb6902d0156537fb312.png

IO流按照操作文件可分为字节流与字符流,其中的字节流与字符流又有许多子类,如缓冲流,转换流,序列化流,压缩流以及打印流等等

字节流与字符流是基本流,他们的子类全都是在他们的基础上改写的

下面我们来一一学习

⑴字节流

⒈字节输入流

字节输入流可以把文件中的数据读取到程序中

FileInputStream:操作本地文件的字节输入流

①构造方法

d17c5354cc4546baabb88c62ac531a7d.png

②常用成员方法

b9c1a743d454448e8456c408d9a851e6.png

400b4d7d060d42e484616af3b6bca467.png 

Ⅰ. read

read读取数据,读取的返回值int是在ASCll上对应的数据,当读到文件末尾了,方法返回-1

因此我们可以根据read的这一特性来读取文件

③如何读取数据?

要利用字节输入流读取文件中的数据

首先我们要创建一个FileInputStream对象,就相当于是程序和文件之间的连接通道

然后我们利用read方法读取数据

最后close关闭通道

其中循环读取数据时,我们可以定义一个变量b用来记录每次read读取的数据,当b=-1时,就表示文件读取完了

Ⅰ.一次读取一个字节

int read()

0237289bec954a5791eeb94fe482e511.png

Ⅱ.一次读取一个字节数组

int read( byte[] bytes)

98108f80095c45b9a3fa404dbd69c1f5.png

⒉字节输出流

字节输出流可以把程序中的数据写入到文件中

FileOutPutStream:操作本地文件的字节输出流

①构造方法

eab639ec7cf748bd824687ede1ddab27.png

创建对象就表示程序与文件之间的连接通道

Ⅰ. FileOutPutStream(File file, boolean append)

其中的第二个参数表示:是否开启续写功能,下面会有对方法的细节说明

②常用成员方法

dec0f6c79ee44a35bb47a0f98c56f7c9.png

e7fb6f7e7c3844939090af9738c6676b.png  

②如何写入数据?

要利用字节输出流将数据写入文件

首先要创建FileOutPutStream对象,连接通道

然后利用write方法将数据写入

最后利用close关流

Ⅰ.一次写一个字节数据

void write(int b)

99a599265f8d4b37a5f60e1a7e21b4f6.png

Ⅱ.一次写一个字节数组

viod write( byte[] bytes)

a2205505dc0a48aca8b065a81b0b8f07.png 

③方法细节

Ⅰ.构造方法细节

FileOutputStream(File file)

如果文件不存在,则创建对象时会自动创建一个新的文件

如果文件存在,则创建对象时会覆盖原来的文件

如图:该方法底层就是调用的可以续写的构造方法FileOutputStream(File file, boolean append),其中的append就是续写的开关

591e091987c8446d97e35f307e85c653.png

因此若我们在创建对象时不想原来的文件被覆盖,我们就可以传递true打开续写的开关

3.结合字节流的文件拷贝

知道了如何利用FileOutputStream和FileInputStream去读写数据,那么这两种方法结合的应用场景有什么?

FileOutputStream与FileInputStream结合的利用场景之一就是文件拷贝

首先利用字节输入流读取文件的数据

然后再利用字节输出流将读取的数据拷贝到我们事先准备好的文件中

最后关流

这样一读一写,就完成了我们文件拷贝的逻辑

32326693f53c4b97a61edcc489e585da.png

⑵字符流

字节流读取数据时,文件中若有中文,就会出现乱码

为了解决字节流读取中文乱码的现象,字符流应运而生,字符流的底层就是字节流,只不过在字节流的基础上多了一个字符集

⒈字符输入流

字符输入流读取数据,一次读取一个字节,遇到中文时,一次读取多个字节

FileReader:操作本地文件的字符输入流

其中的方法细节与字节流一致

①构造方法

c706143c370d4f098169588d363f527b.png 

②常用成员方法

5105d2e8dfad4e9a8eddc91c7c6982f4.png 

read方法读取数据时按照字节进行读取,遇到中文时一次读取多个字节,当读到末尾时返回-1 

③如何读取数据

利用字符输入流读取文件中的数据

首先我们要创建一个FileWriter对象,就相当于是程序和文件之间的连接通道

然后我们利用read方法读取数据

最后close关闭通道

Ⅰ.一次读取一个字符

int read()

9e68a1ec0ee94e68a1b2fcb4034e0eb6.png

空参的read方法一次读取一个字节,遇到中文时一次读取多个字节,并把字节解码转成十进制返回

Ⅱ.一次读取一个字符数组 

int read( char[] chars)

7a4f521408b643968d6e35f5c5f4a7c7.png⒉字符输出流

把数据按照指定的编码方式进行编码,变成字节再写到文件中

FileWriter:操作本地文件的字符输出流

其中的方法细节与字节流一样

①构造方法

accf227c9ec9438b94fb4de0d13a3d0a.png 

②常用成员方法

618e335fe83848cc8502fb0eec75d584.png

1b368a08e0f145809fc1c73d75a72f25.png

Ⅰ. flush

字符流传输数据时,底层会关联文件并创建一个长度为8192的字节数组 

b17c8526601a4049bd8ef243e2fe62e6.png 

读取数据时,read方法会先到缓冲区中读取

若缓冲区中没有数据可以读取,就从文件中读取数据并装到缓冲区中,read方法再到缓冲区中读取数据,若文件中也没有数据了,read方法就会返回-1

flush方法手动将缓冲区里的数据传输到文件当中,这样我们就不用在缓冲区存满的时候才能将数据传输到文件中

如图:我们在运行write方法时,缓冲区会先存满数据,这时文件中是没有写入任何数据的

但当我们手动刷新或关流时,缓冲区里的数据会立刻写入到文件当中

b8a3ed3304724d7e890c04c06401b70a.png

90c7f94c10f248cb9cf4a083b2b99273.png

③如何写入数据

Ⅰ.一次写入一个字符

void write(int c)

3e922a6a104046a6a7595e91a4d500fa.png

Ⅱ.一次写入一个字符数组

void write( char[] chars)

5f312749a60145628d05a99e06d32f21.png

⑶缓冲流

缓冲流分为字节缓冲流与字符缓冲流,底层自带了一个长度为8192的缓冲区用来提高性能,因为字节流的底层没有缓冲区,而字符流有缓冲区,因此缓冲流对于字节流的提升大些

缓冲流是高级流,是在基本流的基础上进行的包装

1.字节缓冲流

⒈1字节缓冲输入流

BufferedInputStream:提高字节流读取数据的性能

①构造方法

5a2c7bc45bb34833a42005bd6cc656cc.png 

其成员方法与FileInputStream一致 

⒈2字节缓冲输出流

BufferedOutputStream:提高字节流写入数据的性能

①构造方法

a53ceba2c24a440db53ca7044131cead.png

②常用成员方法

c6e6e29b351d4ba58f67b2778885403a.png 

在基本流FileOutputStream的基础上多了一个flush手动刷新缓冲区

⒈3缓冲流close方法细节

在缓冲流的close方法底层会先自己关闭基本流,在关闭基本流之后再关闭自己的

39b3ab097d534315ad484eacbb831194.png 

2.字符缓冲流

字符流基本流的底层本来就有缓冲区,因此缓冲流对其的效率提升不是太高

但是其中特有的方法值得我们了解

8abc401773b04f6e8d73ee3b96164c09.png

⒉1字符缓冲输入流

BufferedReader

①构造方法

43795455b4674c76a34d8b2de221c618.png 

②常用成员方法

6324e7f74ba04e0281f2514dc5d05d40.png

Ⅰ. readLine(特有方法)

String readLine() 读取一行数据,读到末尾返回null

方法细节:一次读取一行,遇到回车换行结束,但是回车换行不会读取,需要我们自己手动换行

742579383fce44c6b42e25ac3cece59b.png

⒉2字符缓冲输出流

BufferWrite

①构造方法

49073746d82f4f8280e4f8327eb4f87c.png

②常用成员方法

f4b5956d62ce4220b107490c89bb726c.png

Ⅰ. newLine(特有方法)

void newLine() 跨平台的换行

不同操作系统的回车换行符不同

newLine常常会结合readLine方法使用

045405e540854fb6aca984438e25043c.png

⑷转换流

转换流也是高级流,是字符流与字节流之间的桥梁

⒈字节转换输入流

InputStreamReader:是字节流通向字符流的桥梁,可以使用指定的charset(字符集)读取字节并将其解码为字符

①构造方法

1d81751113be48dd894a1f5e36ff118d.png

② 常用成员方法

0880734b14a445b1b765949b778d45ed.png 

③利用指定的编码方式读取文件

如图:若我们所要读取的文件是属于GBK字符集的,那么利用idea默认的字符集读取是会出现乱码的,因此我们要指定GBK字符集读取

c9a5bdd7ac4940b697aba82b5442e878.png 

⒉字符转换输出流

OutputStreamWrite:是字符流通向字节流的桥梁,可以使用指定的charset(字符集)将要写入流中的字符编码为字节

①构造方法

d544e2da9c894109bba867c6a6b60747.png 

②常用成员方法

dbd849e88f73420aa7fcdeaab4374e3f.png

③利用指定的字符编码写入数据

如图:我们使用GBK字符集写入数据

利用idea默认的字符集去查看文件,会发现写入的文件是乱码现象

bd0ed2e9aefa4f25a2ed58ed07905fea.png

⒊JDK11之后的字符编码读写数据

在JDK11之后为了提高读写的效率,字符流也提供了指定字符编码的性能

如图:对于FileReader和FileWrite,我们可以指定其字符编码方式去读写数据

acce2a902ce946eb99ef9de9a8385b18.png

a9d9132813064b9db76ad7333dec3d33.png 

①不同字符集编码文件的拷贝

如图:我们要利用GBK去读取文件,再利用UTF-8去拷贝文件

b6663822ef504984ad262f359c24cc96.png

⑸序列化流与反序列化流

序列化流与反序列化流是高级流,属于字节流的一种。通过序列化流,我们可以将对象进行保密,通过反序列化流,我们可以将获取保密的对象

⒈序列化流

ObjectOutputStream:可以把对象序列化到本地文件中

①构造方法

b7ac45fd76bd4a549b6aaf7ec87d9189.png 

②特有方法

0608150907c442bc99711a57ebfcc645.png

③如何序列化对象

使用序列化流将对象写到文件时,需要让JavaBean类实现Serializable接口

其中Serializable接口里面没有抽象方法,属于标记型接口,实现了该接口,就表示当前类可以被序列化

如图:我们要将Student对象序列化,就要先在Student类中实现Serializable接口

190aa95b9871466a9272384e06cd7293.png 

然后将要序列化的对象写入本地文件 

0ba18887a48e49c7a92103a6be58533c.png

如图便是序列到本地文件的对象

14c53e2622104aaf93fde8fc13c4ce67.png

注:序列化后的文件不能修改,若修改反序列化就会报错

④SerialVersionUID固定序列号

当序列化运行时,将基于JavaBean类的各个方面会计算该类默认的SerialVersionUID

若我们没有在JavaBean类中显示序列号,那么序列化对象后,当我们修改JavaBean类后,再反序列化获取对象时,程序就会报错,因为修改前后的JavaBean类序列号不同

c8467a85f8c64d0cb6b7bf21b102ed27.png

那么如何让JavaBean类修改后,仍然可以序列化对象呢?

我们可以固定序列号,那么在修改JavaBean类时就不会再计算该类的序列号

c2286d0106e5421ebf79780849f98c55.png

⑤transient瞬态关键字

若在JavaBean中的一些成员变量的值,我们不想将它序列化到本地文件中,那么我们就可以将该成员变量用transient修饰

transient瞬态关键字:不会将当前属性序列化到本地文件中

如图:在JavaBean类中我们将address瞬态修饰

a718252e7dcc4199a01c2aa4b4d6147a.png

然后我们将下面的对象序列化到本地文件当中

1660c9f341c4441483277f8135bfb12b.png

我们再打印出反序列的对象,可以看到我们transient修饰的属性并没有被写到文件中

f31ace0fca0447e79c8f70f566b132b1.png

⒉反序列化流

ObjectInputStream:将序列化的对象读取到程序中

①构造方法

50441a44fc314e6a94c93d571b6f0dee.png 

②特有方法

61b1a2f9e3b44763a157d7fb51e6f124.png

③如何反序列化对象

如图:利用readObject方法读取数据对象存入到集合中来

8ba844d6611e4e01bdfe38ae53b27a7b.png

⑹打印流

打印流属于高级流,只操作文件的目的地不操作数据源

使用打印流写入数据,我们可以方便的打印各种数据值表示形式,以及数据的自动刷新与自动换行

⒈字节打印流

PrintStream :字节打印流

①构造方法

dec9b47381374f60bd3fbcf352138313.png

Ⅰ. PrintStream(File, OutputStream, String) 不带自动刷新的打印流

Ⅱ.PrintStream(OutputStream out,boolean autoFlush)  可以规定是否自动刷新的打印流

Ⅲ.PrintStream(OutputStream out,boolean autoFlush,String encoding)  可以指定编码方式与自动刷新的打印流

注:因为字节流的底层是没有缓冲区的,自动刷新对于字节流来说没有影响

②特有方法

常用成员方法与字节流一样

9e8d883b93564d8ab950c717b9d43164.png

如图演示:我们创建字节打印流的对象并规定编码方式,分别利用write,println, print已经printf方法写入数据

7d4ceaea510a4da78276378df59713fd.png

9108ccb97b88417aad5bb99d269aa67d.png 

⒉字符打印流

PrintWrite:字符打印流

字符流底层有缓冲区,因此相比于字节打印流,字符打印流自动刷新很有必要

字符打印流构造方法与字节打印流一致

特有方法与字节打印流一样

常见成员方法与字符流一样

⒊打印流与输出语句sout

学习完打印流,我们发现打印流中的特有方法与输出语句好像啊,那他们俩之间有什么关系吗?

输出语句: System.out.println()

我们到System类中查找到out变量,发现他是静态的打印流对象

a501c9cdf1eb4e1ab07199ce3453db55.png

那么我们就可以手动获取out对象并调用其中的方法使用

3c7425464b2740d9b97cbb0867882170.png

7ff028a35b9d439ea4940292abc48738.png  

细节:

①利用System.out获取打印流对象,此打印流由虚拟机创建,默认执向控制台

②该流在系统中是唯一的不能被关闭,否则下面将无法打印语句

⑺压缩流与解压缩流

压缩流与解压缩流是高级流,也是字节流的一种

当我们要传输的文件比较大时,我们可以先压缩再传输,当我们接受到文件时再去解压缩文件

压缩包文件以.zip为后缀,压缩包里的每一个文件在java中是一个ZipEntry对象

⒈压缩流

ZipOutputStream:以ZIP文件格式写入文件实现输出流过滤器

①构造方法

6283d8feb68540079a1b1d2cd5cfb660.png

②特有方法

27738e0298a843d0b8aa1e297154b84b.png

③如何压缩文件夹

压缩的本质就是把每一个文件或文件夹转换为Zipr对象放入到压缩包中

如图:压缩到的bbb文件路径后缀为.zip,文件夹bbb里面的文件名不变

5397e34add5e4f558738e89e9394a095.png

要注意的是,当我们把文件转换为ZipEntry对象时,ZipEntry对象的参数就是压缩包内部的路径

a66f0fedd8894cd6a6dac2568293caf0.png

所以在递归中,我们需要传递一个参数name,方便我们以后去规定ZipEntry的路径

3a04e4bda0bd4895a3c49cad7dd778d2.png

如图:我们获取到压缩文件中的所有内容并遍历

若是单级文件则将该文件转换为ZipEntry对象并加入压缩包中

若是多级文件,则递归

18e897fc6dee41879823e06b67ae7478.png

⒉解压缩流

ZipInputStream:读取ZIP文件格式的文件实现输入流过滤器

①构造方法

39962dd3b9834265bf73260150ac4fbb.png

②特有方法

 7271580cb6bd4eac9f97996a07638f96.png

③如何解压文件 

解压的本质就是把每一个ZipEntry对象按照层级拷贝到本地的另一个文件当中

如图:首先我们要创建解压缩的对象并获取压缩包里的每一个ZipEntry对象

因为单级文件可以拷贝

若此ZipEntry对象是多级文件,那么我们就在压缩的目的地创建一个一样的文件夹并向下寻找单级文件

若此ZipEntry对象是单级文件,那么我们就指定路径进行拷贝

28182b11aa0b415794416e3ed5acc1fc.png

注:我们同样可以使用缓冲流提高拷贝效率

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

汤姆大聪明

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

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

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

打赏作者

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

抵扣说明:

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

余额充值