Java基础--IO流
0x00 前言
在学习Java反序列化基础时学习Java的IO流,我认为是很明智的。序列化和反序列化的本质就是数据形式的转换,既然是数据形式的转换,那就必须通过各种IO流来实现。
参考文章(强推):Java(2)-Java IO输入输出流
0x01 IO流概述
数据流概述
IO其实是Input/Output,输入和输出。所谓IO流,就是指输入流和输出流。
输入流和输出流同属于数据流——数据流是一组有序,有起点和终点的字节的数据序列。请看下面的图片:
我们不难想到数据流的三个基本组成部分:数据形式、起点、终点。这里的起点和终点既可以是外部的存储物件,也可以是程序里的内存区,这到底有什么规律呢?
数据存储
数据存储的三种方式:外存,内存,缓存,Java数据的存储同样是这三种。外存指的是硬盘,磁盘,U盘等等,内存在本文就指的是内存区(在电脑上指的是内存条),缓存在CPU里。
IO流概念
经过上面的知识铺垫,我们可以开始了解Java的IO流了。
可能大家会问:把数据存储到程序的内存,但是内存本身就是一个抽象的概念,到底是存储在内存的哪一个物理客体上呢?这就要依靠Java的JVM了,JVM的内存最终是映射到操作系统分配的物理内存上。
对于Java反序列化而言,我们更多把存储在内存理解成存储在内存缓冲区也就是存储在字节数组等等。
但是必须要申明,存储在内存不等同于存储在内存区的缓冲区。缓冲区只是内存的一部分或者是一种特定形式。只是我们在学习Java反序列化时,输入流通常把外部数据输入到程序里的内存缓冲区里——字节数组等等,输出流通常把内存缓冲区的数据输出到外部存储物件上。我们实际上是用一种以点带面的学习。
输入流
抽象理解:
- 把外存的数据读取到内存中的通信通道
- 把数据源的数据读取到程序里的通信通道
具体理解:把外部存储物件的数据读取到内存中的缓冲区以供程序使用的通信通道
输出流
抽象理解:
- 把内存的数据写入到外存的通信通道
- 把程序里的数据写入到外部存储物件上的通信通道
具体理解:把程序里的内存里的缓冲区里的数据写入到外部的存储物件上的通信通道
缓冲区
缓冲区的概念:缓冲区的本质是临时存储数据的内存区域。字节数组本质上就是内存里的一种缓冲区。
0x02 字节流和字符流
前文提了一嘴:
我们不难想到数据流的三个基本组成部分:数据形式、起点、终点。
起点和终点都讲的很清楚了,下面讲讲数据形式。根据数据流中最小的数据单元不同,数据流可以分为两类:
- 字节流:数据流中最小的数据单元是字节
- 字符流:数据流中最小的数据单元是字符
要弄清楚字节流和字符流,就得先弄清楚字节和字符。
字节和字符
1字节等于8比特(1byte == 8bit
)。字节可以表示所有形式的数据,换言之,所有数据形式的底层形式都是以字节表示。
Java里的字符使用Unicode编码,一个字符占用两个字节。字符通常用来表示文本数据,而不能表示音频、图片等数据类型——这些都可以用字节来表示。
综上不难想到,字节流可以转换各种类型的数据,而字符流只能转换文本类型的数据。
字节流
字节流,又称InputStream/OutputStream
。
InputStream
和OutputStream
都是抽象类,必须依靠其子类实现各种功能。
InputStream
(1) public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。
(2) public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的
(3) public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。
(4) public int available( ):返回输入流中可以读取的字节数。注意:若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有用,
(5) public long skip(long n):忽略输入流中的n个字节,返回值是实际忽略的字节数, 跳过一些字节来读取
(6) public int close( ) :我们在使用完后,必须对我们打开的流进行关闭.
子类关系图:
1) FileInputStream:把一个文件作为InputStream,实现对文件的读取操作
2) ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用
3) StringBufferInputStream:把一个String对象作为InputStream
4) PipedInputStream:实现了pipe的概念,主要在线程中使用
5) SequenceInputStream:把多个InputStream合并为一个InputStream
OutputStream
OutputStream提供了3个write方法来做数据的输出,这个是和InputStream是相对应的。
1. public void write(byte b[ ]):将参数b中的字节写到输出流。
2. public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。
3. public abstract void write(int b) :先将int转换为byte类型,把低字节写入到输出流中。
4. public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。
5. public void close( ) : 关闭输出流并释放与流相关的系统资源。
子类关系图:
1)ByteArrayOutputStream:把信息存入内存中的一个缓冲区中
2) FileOutputStream:把信息存入文件中
3)PipedOutputStream:实现了pipe的概念,主要在线程中使用
4)SequenceOutputStream:把多个OutStream合并为一个OutStream
字符流
Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流
与字节流的InputStream和OutStream对应,字符流有Reader和Writer这两个抽象类。
Reader
用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
子类关系图:
Writer
写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
子类关系图:
0x03 结语
终于写完这篇博客了!学习基础需要耐心,加油!