作者 :孙玉昌,昵称【一一哥 】,另外【壹壹哥】也是我哦
千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者
前言
经过前面一系列内容的学习,壹哥相信大家现在已经具备了比较扎实的Java基础了,很多小白也从小班进入到了大班,所以接下来我们就可以学习一些稍微复杂点的知识了。
请注意,前方高能!前方高能!前方高能! 接下来请各位备好晕车药,老司机要飙车了,壹哥这就开始带你学习Java中特别容易让小白头大蒙圈的IO流!
之所以说IO流很让小白头大,主要是因为IO流的内容实在太多了,一会是输入流,一会是输出流,还有字节流、字符流、文件输入流,文件输出流,缓冲流.....呜呜泱泱一大堆。光是IO流中的英文单词都把人看的脑袋都大了,并且很多API的名字又较长又相似,这对初学者来说都是学习中的难点。
但我们在开发时用到IO流的地方确实有很多,比如文件的上传下载,数据传输、存储,音视频编解码等重要操作,另外面试官也很喜欢考察我们对IO流的掌握是否扎实。所以这就需要各位在阅读接下来的几篇文章时,务必打起精神,熬过这个难受的阶段,守得云开见月明哦。
------------------------------前戏已做完,精彩即开始----------------------------
全文大约【4200】 字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......
配套开源项目资料
Github: github.com/SunLtd/Lear...
Gitee: 一一哥/从零开始学Java
我们首先要搞清楚一件事,就是为什么需要IO流这个东西。
我们知道,你可以把数据保存在变量、数组、集合等结构中,但这些结构都是在内存中存储的,里面的数据都是暂时存在的,一旦程序结束这些数据就会消失。所以为了能够永久地保存数据,我们就需要把数据存储到磁盘和文件中,这样就可以长期的使用了。要想把数据从内存中读取写入到磁盘中,这就需要使用IO(输入/输出)流技术了。
但在正式学习IO流的使用之前,壹哥有必要带大家先了解一下IO流的基本概念。
一. IO流概念
首先壹哥 给大家来解释一下 "IO流" 这个概念,如果我们连 IO流 是个啥都不知道,也就没必要继续往下看了。在这里壹哥 会从两部分展开介绍IO流,即 "IO" 与 "流" 。
1. IO
IO其实代表的是两个内容,即 "I" 与 "O",它们分别是 "In" 与 "Out" 的缩写。
In:输入, 代表着能够接收数据的数据源对象,从外部设备把数据输入到内存;
Out:输出, 代表着能够产出数据的数据源对象,从内存中输出数据到外部设备。
对我们来说,大家只需要记住,输入与输出都是以内存为参照物的即可!
2. 流
接下来咱们再来看看什么是 "流"!请先在脑海里想一下,"流"是一种什么样的形态?其实Java中各个API的命名都是很形象的,绝对都做到了见名知意,这里的"流"就是一个很形象的概念!可以说,流是一组有序的数据序列,能把数据从一个地方带到另一个地方。根据数据流向的不同,可以分为输入(Input)流和输出(Output)流两种。
- 输入流:当我们的代码程序需要 读入数据 的时候,可以开启一个连通 数据源 ****的流(输入流) ,这个数据源可以是文件、内存、数据库,或是网络连接。
- 输出流:同样的,当我们的代码程序需要 输出数据 的时候,也可以开启一个连通 目的地 ****的流(输出流), 这个目的地一般是指我们的代码程序。
你可以想象一下,我们的数据好像就是在数据源与目的地之间 "流动" 了起来 。其实 流(stream)这个概念,一开始源于UNIX中的管道(pipe)概念 。 在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备、外部文件等。最后壹哥再给各位提取一下流的概念:
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输的特性可以将流抽象为各种类,方便更直观的进行数据操作。
3. IO流
最后,我们再把IO流的概念梳理一下。
程序中的数据需要移动传输,比如硬盘上的数据需要出现在显示器上,从键盘输入的内容需要存储在硬盘上,所有的这些操作都要进行数据传输,而在Java中负责进行数据传输的技术就是"IO流"。这是一种按顺序读写数据的模式,它的特点是单向流动,数据会像自来水一样在水管中流动,所以我们把它称为IO流。
外部的数据输入到计算机,计算机内部的数据输出到外部,这个实现的过程就是由IO流来完成的,且输入和输出都是以内存为中心的。
- Input输入:是把数据从各种外部的输入设备(键盘、麦克风等)中读入到内存,例如,把文件从硬盘读取到内存,从网络读取数据到内存等;
- Output输出:指把数据从内存输出到各种外部设备(如显示器、磁盘等),例如,把数据从内存写入到文件,把数据从内存输出到网络等。
我们之所以要以内存为中心,是因为代码要运行在内存中,这就需要各种数据都必须进入到内存中进行处理。大家要注意,IO流对数据的处理,只能按照数据序列的顺序来进行,即前一个数据处理完之后才能处理后一个数据,否则会产生异常。
二. 作用
那么根据上面壹哥对IO流的描述,我们就可以搞清楚出IO流的核心作用,如下:
IO流可以在数据源和目的地之间搭建一个传输通道,用于处理设备与代码程序之间的数据传输,设备是指硬盘、内存、数据库、键盘录入、网络等。
一言以蔽之,IO流屏蔽了实际的设备处理数据细节,我们不必关心其内部具体的流动过程,只需知道IO流是用来处理设备之间数据传输的即可。
三. 分类
如果你只看上面IO流的概念,感觉也没有什么难度,但是关于IO流的学习,最难的是分类太多。IO流有着不同的划分维度,如果我们根据这些不同的标准来分类的话,可以分类如下:
- 按IO流的流动方向分为: 输入流和输出流;
- 按IO流的数据单位分为: 字节流和字符流;
- 按IO流的不同功能分为: 节点流和处理流。
接下来 壹哥 会分别解释一下这几种类型。
1. 输入流与输出流
从IO流的流动方向上,我们知道IO流可以分为输入流与输出流,但不少初学者总是分不清输入流与输出流,甚至会把两者搞反。所以接下来 壹哥 就再明确一下输入流与输出流的区别,我们来看下图:
在上图中,我们以家中自来水的进水与出水来形象的比喻输入流与输出流。
- 自来水公司相当于是数据源,我们家中的房子就相当于是目的地;
- 自来水公司的水进入到我们家里,这就是自来水的输入;
- 我们家中产生的污水,要排到污水处理厂,这就是自来水的输出。
在这个供水、排水的过程中,我们可以想一下,输入、输出是不是一个相对的概念呢?那么相对于哪个角色呢?没错!输入、输出都是相对于我们的房子来说的,进入到房子叫做输入,从房子流出就叫做输出。所以房子就是输入和输出的参照物,这就和内存是IO流的输入、输出参照物一样!
最后,壹哥 再把上图中的各角色明确一下:
- 数据源: 上图中自来水公司的水池,用于提供自来水(数据);
- 输入流: 从自来水公司进到房子里的管道,携带着具体的数据家里来;
- 目的地: 上图中的房子,这代表着我们项目的代码程序,或者说是内存;
- 输出流: 从家中流出到污水厂的管道流,携带着具体的数据到污水厂;
- 数据目标: 最后的污水厂,这是用于持久化存储污水(数据)的地方,其实也是一种数据源。
所以,IO流中的输入流与输出流,入与出都是相对于内存而言的。从某个数据源读取数据到内存中,被称为输入流;从内存中把数据持久化保存到其他设备上,则被称为输出流。简单一句话,流向内存是输入流,流出内存的输出流。 我们再来看下图:
另外要注意,我们可以从输入流中读取信息,但不能对它写;可以对输出流进行写操作,但不能对其读。所以输入也叫做读取数据,输出也叫做作写出数据!
至此,你应该不会再把输入流和输出流搞反了吧,是不是应该给 壹哥 点个赞呢,hiahia......
2. 字节流与字符流
上面 壹哥 说了,按照数据流的数据单位不同,可以把IO流分为字节流与字符流,两者的区别如下:
- 字节流: 字节流是以字节(8bit)为单位进行数据的按序传输,一次读取或写入一个字节(8位)的二进制数据, 字节流能处理所有类型的数据(如图片、音频、视频等) ;
- 字符流: 字符流以字符为单位进行数据的按序传输,根据码表映射字符,一次读取或写入一个字符(可能是多个字节),一次读入或写出16位二进制数据, 字符流只能处理文本文件中的字符类型数据 。
字节流和字符流的这些区别,主要是因为Java一个字节的空间是1个Byte,即8位;而一个字符的空间是2个Byte,即16位。另外Java的字节是有符号类型,字符是无符号类型!
另外我们还知道,计算机中的一切文件数据(文本、图片、视频等)在存储时,都是以二进制的形式保存的,即都是一个一个的字节,在传输时也同样如此。所以,字节流可以传输任意类型的文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流,底层传输的始终为二进制数据。
但如果我们需要读写的内容是字符,并且字符不全是单字节表示的ASCII字符。有很多的字符是用Unicode编码表示的,采用的是双字节,而InputerStream是用来处理单字节的,在处理字符文本时不是很方便,所以就需要有一种可以高效处理字符的流。字符流的本质其实也是基于字节流的 ,所以字节流和字符流的原理其实也是相同的,只不过处理的数据单位大小不同而已。一般情况下,Java所有关于IO流的API,后缀是Stream的是字节流,后缀是Reader和Writer的是字符流。但你可能会问,我们在开发时,到底是要选择字节流还是字符流呢?
答案就是,对于字节流和字符流,如果我们只是想处理纯文本数据,可以优先考虑字符流,除此之外尽量使用字节流。
3. 节点流与处理流
另外如果从IO流的功能角度来看,IO流可以分为节点流和处理流,两者有以下区别。
节点流,可以直接与数据源相连,进行读入或写出。
但如果我们直接使用节点流进行操作,读写并不方便,所以为了更快的读写文件,就有了处理流。
处理流,一般会与节点流一起使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。
四. 使用场景
总之,Java中有种类丰富且功能强大的IO流机制,包含了多种流类型,例如:字节流、字符流、缓冲流、数据流、对象流等。我们利用这些流,可以进行文件读写、网络传输、图片处理、音频视频处理等场景。
------------------------------正片已结束,来根事后烟----------------------------
五. 结语
至此,壹哥就在今天的这篇文章中给大家科普了IO流的基本概念,今天的重点如下:
- IO流是一种流式的数据输入/输出模型,负责在数据源和目的地之间搭建一个传输通道,用于处理设备与代码程序之间的数据传输;
- 输入与输出都是针对内存而言的;
- 字节流是以字节(8bit)为单位进行数据的按序传输,一次读取或写入一个字节(8位)的二进制数据;
- 字符流以字符为单位进行数据的按序传输,根据码表映射字符,一次读取或写入一个字符(可能是多个字节)。
在下一篇文章中,壹哥 会给大家介绍IO流相关的API类,敬请继续关注哦。另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。