以前学习 Java 中文件和流的时候,理解不深,当时又觉得很少用 Java 操作文件,所以就没有好好看,导致对于“文件”和“流”这两个概念都分不清。
印象中只记得有好多个类,记不得有多少个,更分不清各自有什么用,结果现在看不懂别人的代码了,所以再学习一下,争取能看懂。
文件和流
Java 提供了文件相关的类,和流相关的类,以前感觉都差不多。实际上前者主要是操作文件(比如删除、复制等),而不是进入文件中读取文件的数据。而后者是读写文件中的内容。
假设有一个 a.txt 文件,与文件相关的类,可以将它删除、改名。而与流相关的类,可以读取 a.txt 里面的内容,或者修改 a.txt 里面的内容。
上面是 Java 中类的区别,那么“文件”和“流”这两个名词各自是什么意思呢?
文件就是电脑里存在的文件:文本文件、图片文件、视频文件等等。
至于流,真的不好理解,网上有些说对数据的读、写是流,有的说文件就是流,以前认为流是内存和数据之间的通道。整半天没搞懂,迫于找不到通俗易懂的解释,所以根据网上的理解,自己瞎猜。
从实际应用的角度看,程序可能需要从外部读取数据,比如从硬盘中读取数据、从网络中获取数据。这些操作类似,不如将它们抽象化,用一个类表示,这也刚好符合面向对象的思想。
看到这里,我想说的是,不要单独去理解什么是流。(忘掉流吧,我偷电瓶养你)
直接从 InputStream 开始理解,它是一个抽象类,既然是类就应该可以用来表示某一类事物(就像 Person 类可以表示人一样)。所以 InputStream 就可以看成是所有可以读取到数据的东西。不过是硬盘,还是键盘,只要我可以从你那里读取到数据,你就是 InputStream(输入流)。
OutputStream 也是同样的道理,我往硬盘写数据的时候,硬盘就是 OutputStream(输出流)。
理解的前提是忘掉“流”,“流”只不过是类名里的最后一个字,如果设计者喜欢,叫做 OutputBlock 又有何不可呢?其次是牢记在 Java 中类是为了表示一类事物,InputStream 和 OutputStream 也不例外。
常见的类及其描述
Some important Byte stream classes.
Stream class | Description |
---|---|
BufferedInputStream | Used for Buffered Input Stream. |
BufferedOutputStream | Used for Buffered Output Stream. |
DataInputStream | Contains method for reading java standard datatype |
DataOutputStream | An output stream that contain method for writing java standard data type |
FileInputStream | Input stream that reads from a file |
FileOutputStream | Output stream that write to a file. |
InputStream | Abstract class that describe stream input. |
OutputStream | Abstract class that describe stream output. |
PrintStream | Output Stream that contain print() and println() method |
Some important Charcter stream classes.
Stream class | Description |
---|---|
BufferedReader | Handles buffered input stream. |
BufferedWriter | Handles buffered output stream. |
FileReader | Input stream that reads from file. |
FileWriter | Output stream that writes to file. |
InputStreamReader | Input stream that translate byte to character |
OutputStreamReader | Output stream that translate character to byte. |
PrintWriter | Output Stream that contain print() and println() method. |
Reader | Abstract class that define character stream input |
Writer | Abstract class that define character stream output |
具体的类就不研究怎么用了,估计使用得最多的就是 Bufferedxxx 了。
示例
下面这段代码的意思是:
- 获取到字节输入流
- 将字节输入流转换成字符输入流
- 再转换成缓冲字符输入流
- 然后在逐行读取内容
1 | InputStream inputStream = request.getInputStream(); |
创建一个 BufferedReader 之前还要先创建一个 InputStreamReader,这看起来很麻烦,为什么不直接创建缓冲字符输入流呢?
首先,因为要从不同的设备中读取数据,所以需要设计多个类,而每个类都可能需要用到缓冲这个功能,如果再为每个类设计一个具有缓冲功能的类,那么类的数目将会翻一倍。
所以 BufferedReader 被设计为:接收一个字符输入流,并具有缓冲的功能,虽然使用上麻烦了一点,但是还是可以接受的,不然更多的类需要去记。