一、啥是I/O
概念:I/O为输入,输出流的统称,流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。
本质:本质是数据传输,即数据在两设备间的传输称为流,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
分类:
根据处理数据类型的不同分为:
- 字符流【字符流以字符为单位,且只能处理字符类型的数据】
- 字节流【字节流以字节(8bit)为单位,能处理所有类型的数据(如图片、avi等)】
根据数据流向不同分为:
- 输入流【只能进行读操作】
- 输出流【只能进行写操作】
结构导图:
二、流类型详解
流转换
定义:InputStreamReader和OutputStreamWriter是字符和字节的桥梁,也可称之为字符转换流。
原理:字节流+编码。在读和写的过程中使用指定的charset(字符集),来操作字节与字符之间的转换。
调优:可以考虑在转换流的外层包装一层缓存流,避免频繁转换调用
对象序列化
定义:将一个对象写出,或者读取一个对象到程序中。也就是执行了序列化和反序列化的操作。
使用方式:
- 读:ObjectInputStream.readObject()
- 写:ObjectOutputStream.writeObject()
PS:只有实现了 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取,且必须要使用相对应的对象输入输出流才可正常操作对象。
PS:输出输入的内容在文本编辑器打开是二进制的形式,所以看着像乱码,这是正常的,若只要对象的内容应选用PrintStream。
public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException { /*写*/ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\Users\Administrator\Desktop\testObjectOutputStream.txt"));//创建对象输出流 String[] arr = {"abc", "bde"}; List<String> list = Arrays.asList(arr); oos.writeObject(list); oos.flush(); oos.close(); /*读*/ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\Users\Administrator\Desktop\testObjectOutputStream.txt")); System.out.println((List) ois.readObject()); } }
写到文件中的内容:
缓冲流
定义:一种使用内存机制(内存缓冲)来操作流的特殊流
原理:
- 使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区的数组内。
- 通过缓冲区的read()或者方法从缓冲区获取具体的字符数据,这样就提高了效率。
- 如果用read方法读取字符数据,并存储到另一个容器中,直到读取到了换行符时,将另一个容器临时存储的数据转成字符串返回,就形成了readLine()功能。
使用方式:通常用作其他流的2次封装,利用内存机制来提高流的读写效率。
基本数据操作
定义:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型(其他数据类型就不支持了,如要读一个图片那就凉了...)。
/** * 测试(DataInputStream/DataOutputStream)读写基础java数据类型 */ public class Test { public static void main(String args[]) throws IOException { /*使用桌面文件创建一个输入流*/ DataInputStream in = new DataInputStream(new FileInputStream("C:\Users\Administrator\Desktop\testObjectOutputStream.txt")); /*创建一个输出流(PS:这里这个文件并没有存在于桌面上,运行时会自动创建并写入信息)*/ DataOutputStream out = new DataOutputStream(new FileOutputStream("C:\Users\Administrator\Desktop\testObjectOutputStream1.txt")); /*用缓存机制来优化一个可能开销很大的输入流*/ BufferedReader d = new BufferedReader(new InputStreamReader(in)); /*读取输入流内容,并把内容转换为大写,在控制台输出并写入新文件*/ String count; while ((count = d.readLine()) != null) { String u = count.toUpperCase(); System.out.println(u); out.writeBytes(u + " ,"); } d.close(); out.close(); } }
打印控制
定义:一种主要用于输出的流
特点:除了保留Ouput流的基础方法,还添加了一组print()/println()方法,且不会抛出异常,方法内部实现已经有try{}catch块。
/** * 测试打印输出流 */ public class Test { public static void main(String args[]) throws IOException { //构建一个字符输出流(字节输出流同理,不在演示) Writer w = new FileWriter("C:\Users\Administrator\Desktop\testObjectOutputStream.txt"); //优化:构建缓冲流 BufferedWriter bw = new BufferedWriter(w); //构建字符打印流,用于向指定文件输出内容 PrintWriter pw = new PrintWriter(bw); //println会换行输出,print不会换行 pw.println(true);//写入boolean型 pw.println("测试和写入");//写入字符串 pw.println(123);//写入int类型 //关闭流 pw.close(); bw.close(); w.close(); } }
文件操作
定义:即专门操作文件的一组流
使用方式:
/** * 测试文件流 */ public class Test { public static void main(String args[]) throws IOException { /*简单演示常用文件流的构造方法,输出流同理不在描述*/ //使用(绝对/相对)路径的方式构建文件输入流 FileInputStream fileInputStream1 = new FileInputStream("D:\log.txt"); //使用文件对象构建文件输入流 FileInputStream fileInputStream2 = new FileInputStream(new File("D:\log.txt")); } }
数组操作
定义:操作字节/字符数组的一组流
原理:流在内存中创建一个字节数组缓冲区,需要读/写的数据保存在该字节数组缓冲区中。
管道操作
定义:一种可以让多线程通过管道进行线程间的通讯的流,必须结合使用
管道流的详细讲解可以看这里~,讲解得非常详细,非多线程编程使用的场景较少,可作为了解。
参考资料: