【字节和字符】IO(输入输出)中的字符流和字节流
当操作不涉及用户的输入来操作文件(例如就想将从a.mp4复制出一个aa.mp4)时,使用字节流和字符流的原理都很好理解。 inputstream和outputstream(输入和输出流)就像是一个人的左右手。
左手是inputstream,用于拿原始文件的内容,而outputstream就像是右手,将左手传递来的东西放入到右边。这样就实现将物件从左放到右(也就是实现了数据的传输)。使用字节流的方式进行操作时,“左手”(FileInputstream)先从文件中“拿取”原始的01010格式的内容,然后"右手"(FileOutputStream)原封不动将这些信息进行传递。
最原始的方法就是左手拿一个,然后交给右手,然后左手再拿一个,再给右手,这样一个一个字节的读取,但是速度很慢。
所以可以人为在程序中设置缓冲区的大小,就好像在两边都增加一个箱子。等左边箱子装满了转移到右边。那么转移的次数就大大减少了,需要的时间也就缩短了。更便捷的做法是直接使用字节缓冲流(BufferedInputStream),它自身定义了一个大小为8192的字节数组作为缓冲区,无需自己再设置缓冲区大小。
2.1.2 字符流
接下来我们换一个工人,他的左手和右手分别对应字符流FileReader和FileWriter。虽然说是字符流,但是左手拿到的仍旧是010100形式的字节。由于右手只能够传递字节,这时候就需要在程序中手动设置,将左手拿到的字节转化成字符。
(后面会有其他的字符流可以简化这个工作,甚至像bufferedReader之类的包装流可以直接读取字符格式,不需要再转化成字符流)。 从上面来看,字节流的操作明显要简单,而且还适用于音频、视频等多种格式的文件。而字符流应用于文本文件。那为什么还要字符流呢。注意,这是因为这里没有涉及用户输入等操作。
注: 经过装饰设计模式后的 BufferReader类,就有了readLine方法,这个方法就能够读取整行,并且返回的还是String格式。所以相应的其判断到文件末尾的方法也由上面的while(len=in.
read()!= -1)变成了while((str=br.readLine()) != null)。也即是说,原来的bufferedInputStream文件拷贝过程是纯字节的过程,左手拿到的是二进制数组,右手出去的还是二进制数组(缓冲区内容就是二进制数组,默认8192个字节数组)。
而现在bufferedreader是纯字节的过程。左手拿到的是字符串,右手出去的还是字符串。缓冲区内容现在不再是固定长度的字符串,而被规定为一行(这个说法不准确,可能本身也有固定的缓冲区)。
可见,其实bufferedreader是专门针对文本文档设计的。而Bufferedinputstream的适用范围要更广,不仅可以用于文本,还可以用于图片、视频等各种文件。
当涉及用户输入输出时,情况就不一样了。举个例子,复制文件内容并且在cmd窗口打印出来,以String格式显示给用户,这就涉及用户输出。而当我们编辑文本并保存的时候,我们输入的是String格式的内容,但是文本最终需要保存为二进制文件(还是上面所说的,所有文件都以二进制形式存在)。
这又涉及用户输入的问题。 例如当我们想将String格式的内容(例如下面的"what are you doing")来写入文件时,如果使用字节输出流FileOutputStream的话需要先将字符串转换为字节(二进制)数组,然后再进行写入。
而字符流不需要这么麻烦,同样上面的效果,只需要:
(当然,别忘了文件都是以二进制格式存在的,所以这里字符-->字节的过程只是在程序中被“省略”了而已)