IO
Java流操作有关的类和接口
类 | 说明 |
File | 文件类 |
RandomAccessFile | 随机存取文件类 |
InputStream | 字节输入流 |
OutputStream | 字节输出流 |
Reader | 字符输入流 |
Writer | 字符输出流 |
Java流类库结构图:
流的概念和作用
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。
即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
IO流的分类
- 根据处理数据类型的不同分为:字符流和字节流
- 根据数据流向不同分为:输入流和输出流
字符流和字节流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:
- 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
- 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
输入流和输出流
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
关于File
File包括文件和目录,对文件和目录的操作是新建目录mkdir,新建文件createNewFile,删除文件和目录delete。
BufferedInputStream
==============================
BufferedInputStream对外提供滑动读取的功能,通过预先读入一整段原始输入流数据至缓冲区中,而外界对BufferedInputStream的读取操作实际上是在缓冲区上进行,如果读取的数据超过了缓冲区的范围,那么BufferedInputStream负责重新从原始输入流中载入下一截数据填充缓冲区,然后外界继续通过缓冲区进行数据读取。
这样的设计的好处是:避免了大量的磁盘IO,因为原始的InputStream类实现的read是即时读取的,即每一次读取都会是一次磁盘IO操作(哪怕只读取了1个字节的数据),可想而知,如果数据量巨大,这样的磁盘消耗非常可怕。
而通过缓冲区的实现,读取可以读取缓冲区中的内容,当读取超过缓冲区的内容后再进行一次磁盘IO,载入一段数据填充缓冲,那么下一次读取一般情况下就直接可以从缓冲区读取,减少了磁盘IO。
说白了buffered就是用来缓存的,可以用来提高读取的效率,之所以说FileInputStream是阻塞的方法是因为CUP的速度和磁盘的速度是不匹配的,如果每次要读取的时候都访问磁盘这样就造成了阻塞。
通过以上的说明可以看出buffered则并不是阻塞的。所以我们读取文件的时候一般都在文件流上边套上一层buffer流。
==============================
数据在硬盘上都是以字节的方式存储的,那么什么时候使用字符流,什么时候使用字节流呢?
字符流是对字符操作的,也就是对文本文件或者其他字符文件操作。
而对于图片,声音,视频这些文件则用字节流操作。
接下来是对字符流的操作,字符流相当于是字节流+编码表。
可以向文件中直接写入字符串。读取的时候注意是用字符数组接受,不是字节数组。
1 package qugeng; 2 3 import java.io.File; 4 import java.io.FileReader; 5 import java.io.FileWriter; 6 import java.io.IOException; 7 8 public class Test { 9 10 public static void main(String[] args) throws IOException { 11 File file = new File("file.txt"); 12 13 FileReader reader = new FileReader(file); 14 FileWriter writer = new FileWriter("2.txt"); 15 16 int len; 17 char[] buf = new char[1024]; 18 while ((len = reader.read(buf)) != -1) { 19 System.out.println(new String(buf, 0, len)); 20 writer.write(buf, 0, len); 21 } 22 writer.write("\r\n" + "end"); 23 reader.close(); 24 writer.close(); 25 } 26 }
以下是缓冲的字符流。经过缓冲以后可以读取和写入一行的数据
package qugeng; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { File file = new File("file.txt"); BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); BufferedWriter bufferWriter = new BufferedWriter( new FileWriter("2.txt")); String buf; while ((buf = bufferedReader.readLine()) != null) { bufferWriter.write(buf); bufferWriter.newLine(); System.out.println(buf); } bufferedReader.close(); bufferWriter.close(); } }
最后解决的一个问题是字节流和字符流的转化,使用的是InputStreamReader和OutputStreamWriter,它们本身属于的是reader和writer字符流。
之所以会用到这些转化流是因为系统有时候只给我们提供了字节流,为了方便操作,要用到字符流。
比如说System.in标准输入流就是字节流。你想从那里得到用户在键盘上的输入,只能是以转换流将它转换为Reader以方便自己的程序读取输入。
再比如说Socket里的getInputStream()很明显只给你提供字节流,你要想读取字符,就得给他套个InputStreamReader()用来读取。