缓冲区
遇到与底层相关的概念,往往都很模糊,所以才想要把这个问题解决清楚;
那么什么是缓冲区呢,我为什么会有这样的疑问呢;接触到Java的I/O流,其中底层是怎么实现的,其中BufferedReader中的Buffered是什么意思,C语言中的输入、输出底层是什么实现的,它们跟缓冲有什么关系;
缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对I/O的数据做临时存储,这部分预留的内存空间叫缓冲区。
对于scanf()来说,它是从缓冲区里读取数据到对应的变量里,如果缓冲区没有数据,这时候执行scanf(),它会因读取不到数据而一直等待,从而发生死锁;
Java File类
在java中,File对象是一个对文件或者目录名的抽象,在windows中即是文件夹,它不是真实硬盘里的文件或者文件夹,File实例是在内存中new出来的一个对象,实际上它只是 与硬盘上的文件或者文件夹进行了映射,它的构造函数参见File类构造函数,他不含有无参的构造函数,即它这个new出来的对象,根据构造函数参数代表的文件进行映射,如果文件不存在,那么对于这个file实例来说,它不会发生错误,它的属性依然拥有默认值,不过当如果通过流去读取时,会发生错误;构造函数参数文件名,不区分大小写。
1 | import java.io.*; |
Java 文件流
分为字节型文件流和字符型文件流;
文件存在的原因,是因为文件存储在硬盘上,是永久保存的,而类似变量、集合,都是暂时性地存储,并且文件可以存储很多份地信息。
对于文件的读取,实际上是将文件里的信息读取,存到内存中的集合等容器中,然后对此容器进行操作,此容器相当于缓存。而文件流即是对于文件的读取或者写入。
字节型文件流
FileInputStream/FileOutputStream
- FileInputStream是InputStream的子类,字节型输入流都是InputStream的子类。它的构造函数有三个,分别是字符串、file对象,第三个不做了解;
- FileInputStream.read(),java对该方法进行了重载,对于不带参数的方法,为读取一个字节,返回值为读取字节对应的Unicode;实际上都是当作字符来读取,如果读取到汉字,而汉字编码又不是一个字节的情况下,那么仅读取该汉字的一字节的数据,如果输出这个单字节数据的Unicode码对应的char,可能会是乱码;对于带参数的情况,参数可以是一个byte数组,即一次性读取byte数组大小的数据,并存到该byte数组中;
如图,使用一个3字节大小的byte数组去成功读取一个汉字,所以,可以想到的是,如果我们去读取1字节,那么仅仅是该汉字的一部分;
1 | import java.io.*; |
同FileInputStream,FileOutputStream是OutputStream的子类,字节型输出流都是OutputStream的子类;在这里,如果创建文件输出流,文件路径不存在,则创建该文件;对于FileInputStream则会抛出异常;并且,FileOutputStream实例含有一个两个参数的构造函数,第一个参数为文件路径,第二个参数为一个布尔型,为true代表可追加,否则每次新建一个文件输出流,文件内容都会被清空。
- FileOutputStream,该类构造函数第一种,参数为File类实例,还有一个boolean参数 默认false,第二种构造函数和第一种类似,不过把File换成了String;
1 | import java.io.*; |
字符型文件流
FileReader/FileWriter;
FileReader是字符型文件输入流,是InputStreamReader的子类,而InputStreamReader是Reader的子类,它含有两个构造函数,第一种,含一个参数是String,即文件路径,第二种参数是一个File实例;
FileReader.read(),对于它不含参数的方法,读取一个字符,返回值为该字符的Unicode码;对于含参数的方法,它的参数应该是一个空的char数组,即将通过流将文件中字符读到char数组中,返回值为读取的有效字符数;
FileWriter,常用方法,FileWriter.wirte(),参数可以是你想要写到文件里的字符对应的Unicode码,或者是一个字符数组,或者是一个String,不能是字符;
1 | import java.io.*; |
Java 缓冲流
同样的,也分为字节型缓冲流和字符型缓冲流,BufferedInputStream/BufferedOutputStream,BufferedReader/BufferedWriter;
使用缓冲的目的即是为了提高速度,比如,一次读取很多字节,但不写入磁盘,先放到内存中,等凑够了缓冲区的大小一次性写入磁盘,这样减少了磁盘操作次数,会提高速度;
所以,缓冲流就是实现了缓冲功能的输入流和输出流,使用带缓冲的输入输出流,效率更高速度更快。
BufferedInputStream/BufferedOutputStream
本质上是通过一个内部缓冲字节数组实现的,那么BufferedReader/BufferedWriter
本质上是通过一个内部缓冲字符数组实现的。具体参见java API;
需要注意,缓冲流的构造函数的参数需要是一个文件流的实例;
Java序列化与反序列化
之前学过了也讲过了\(\dots\)