常见I/O流的梳理
引言:对于I/O,新手会用但不知道原理,平时看代码就看的很痛苦,一用就要去查。
eg:
File file = new File("xxx");
OutputStream outputStream = new FileOutputStream(file);
这个还好,这两个呢?
Writer out = new OutputStreamWriter(new FileOutputStream(new File("xxx")));
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
反正笔者是看的很头疼,所以写来梳理常见的I/O流及用法
tip:这种一次套用多个方法属于代码链,建议掌握;因为虽然能拆分代码,但很繁琐(看别人代码也多数是代码链)
字节流和字符流
- 字节流 :InputStream , OutputStream
- 字节流 :Writer , Reader
首先很重要的概念,上述的都是抽象类,这也是为什么每次都需要通过子类来创建对象的原因(常见的就是FileXxx)
File file = new File("xxx");
OutputStream outputStream = new FileOutputStream(file);
上文中的代码现在也就能理解了
区别:
数据传输中都是使用字节数据,而程序中往往使用的是字符数据类型。
而最大的区别就是字符流使用了缓冲区,对于字符输出流需要显式调用flush() ,才能输出数据(或者字符流关闭时强制刷新)
关联
转换流,为了解决两种流的转换,就应运而生。
转换流
OutputStreamWriter , InputStreamReader
以下是源码片段:
public class OutputStreamWriter extends Writer{
public OutputStreamWriter(OutputStream out)
}
public class InputStreamReader extends Reader{
public InputStreamReader(InputStream in)
}
即:转换流都是对应字符流的子类,
而且可以通过构造方法接收对应字节流的类实例
即:
xxxStreamXxxer的转换器接收的其实是xxxStream的具体子类
eg:
File file = new File("xxx");
FileOutputStream fileOutputStream = new FileOutputStream(file);
Writer out = new OutputStreamWriter(fileOutputStream);
等价于开始的代码:
Writer out = new OutputStreamWriter(new FileOutputStream(new File("xxx")));
现在是不是就理解一点了?
打印流
输出数据时,OutputStream只允许输出字节数据,而Writer只允许输出字符数据和字符串数据。而其它类型的数据(整数,浮点数等)怎么办呢?为了简化输出,打印流就被设计出来了。
打印流类 : PrintStream , PrintWriter
(关于两者的区别,笔者也不太懂,就不班门弄斧了。)
那既然是为了简化输出,那理所当然的,两者的构造方法都能接受包括File 、OutputStream、Writer。
而最重要的一些方法:
public void print(数据类型 变量)
public void println(数据类型 变量)
也被重载多次,能输出任意类型的数据。
System类对I/O的支持
趁热打铁,看到上面的print,println,有没有一点熟悉的感觉?
System.out.println();
常量 | 类型 | 描述 |
---|---|---|
public static final PrintStream err | 常量 | 错误输出 |
public static final PrintStream out | 常量 | 系统输出 |
public static final InputStream in | 常量 | 系统输入 |
没错,System.out 其实就是PrintStream类, 然后调用println()的方法
所以System.out.println() 实际上就是利用了I/O操作的输出
而System.in是InputStream,即输入字节流,但正如前文所说,对中文的处理不够好,所以就需要包装成别的流,常见的就是借助BufferedReader 缓冲输入流
缓冲流Bufferxxx
包含:BufferedInputStream,BufferedOutputStream,BuffredRead,BufferedWriter
此处只讲
BufferedReader 缓冲输入流:
提供了一种字符流的缓冲区数据读取,进行数据读取时,会将读取到的数据暂时保存在缓冲区中,然后可以将内容一次性取出.
public class BufferedReader extends Reader {
public BufferedReader(Reader in)
public String readLine() throws IOException {
}
}
如源码所示,该类定义的构造方法只能接受Reader的实例
而对System.in常见的处理之一就是:
先使用转换流:InputStreamReader把System.in变为字符流,再用BufferReader包装起来
InputStream inputStream = System.in;
Reader reader = new InputStreamReader(inputStream);
BufferedReader input = new BufferedReader(reader);
就等价于开头的最后一个代码
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
之后就可以利用**BufferReader提供的readLine()**接受输入信息
eg:
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String msg = input.readLine();
System.out.println(msg);
(键盘输入:原来如此)
执行结果:
原来如此
Scanner输入流工具
对于System.in相信各位用得更多的还是
Scanner scanner = new Scanner(System.in);
Scanner,如其名,是专门的输入数据类,构造方法中可以接受File、InputStream、Readable(Reader实现的接口之一)类型的输入实例。
除了完成输入数据操作外,也可以很方便地对输入数据进行验证。此处不展开讲,不过建议读者好好学习一下,很实用的一个工具类。
结语
本文并没有对I/O流的各种类,如内存操作流、管道流等说明,也没有引入相关的UML图跟各个类的常用方法,后续可能会补出一篇相关的内容。
因为本文主要用于梳理常用流的关系跟包装关系等,鉴于笔者的水平也不够,可能有错误,欢迎大家指出
第一次写博客,谢谢大家,希望多多包涵