整个大的分类,不二话,还是那四个,InputStream,OutputStream,Reader,Writer是所有流的基类(别抬杠,我知道RandomAccessFile除外)具体用到什么功能,就要去对InputSteam的方法进行重写,使用他们子类来完成。在这里我来整理一下提他们之间的关系和用法。
一、InputStream
BufferedInputStream | 字节缓冲输入流 | |
InputStream | FileInputStream | 字节文件输入流 |
ByteArrayInputStream | 字节数组输入流 |
其中BufferedInputStream应该是大家最经常用到的,为的是在使用InputStream时可以增加缓冲区,好处就是在于可以减少系统开支,增加效率,打个比喻,如果不用缓冲就像是一捧一捧的舀水,而用缓冲就像是一桶一桶的舀水,就可以减少两边来回跑的时间,也就是通过这样的方式来增加I/O效率。
FileInputStram则是文件输入流了,在读入流文件的时候就需要他了(如影音,图片等文件),通常可以把他再套上BufferedInputStream使用。
BufferedInputStream bis = new BufferedInputStream(System.in);
因为BufferedInputStream 的默认缓冲区大小是8092KB也就是8M,所以在文件较小的时候(相较于8M)用过BufferedInputStream之后的I/O操作明显效率会比直接用FIleInputStream提高了很多,在等于8M或者大于8M的时候相差就不大了,但是整体来说还是推荐用BufferedInputStream的。
BtyeArrayInputStream 这个起到字节与流之间的桥梁,可以将字节数组转换成流。
InputStream is = new ByteArrayInputStream(new byte[1024]);
new String(is.toString().getBytes(),"UTF-8");
二、OutputStream
BufferedOutputStream字节缓冲输出流FileOutputStream字节文件输出流ByteArrayOutputStream字节数组输出流
同样的,BufferedOutputStream是大家经常用到的,与BufferedInputStream同理,增加缓冲区,减少系统开支,增加I/O效率。
FileOutputStream则是文件输出流,在写出文件的用的就是他,也是通常可以把他套上BufferedOutputStream使用。
BufferedOutputStream bis = new BufferedOutputStream(new FileOutputStream(""));
ByteArrayOutputStream 你可以将要输出的字节数组读到内存缓冲区,然后要进行你所需要的操作。
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(new byte[1024]);
三、Reader
BufferedReader | 字符缓冲流 | |
Reader | InputStreamReader | 字节->字符输入流 |
FileReader | 字符文件输入流 |
Reader也同样提供了对应的字符缓冲流来提高效率。
InputStreamReader则是搭起了字节流与字符流的桥梁。
Reader reader = new InputStreamReader(System.in);
FileReader是当读取文件为文本文件时(如TXT文件),可以直接用FIleReader进行操作,同样的在外面可以套上BufferedReader进行使用。
BufferedReader br= new BufferedReader(new FileReader(""));
BufferedWriter | 字符输出流 | |
Writer | OutputStreamWriter | 字节->字符输出流 |
FileWriter | 字符文件输出流 | |
PrintWriter | 打印流 |
Writer有他对应的BufferedWriter来增加I/O效率。
OutputStreamWriter也是搭起了字符流与字节流的桥梁。
Writer writer = new OutputStreamWriter(System.err);
FileWriter是需要将字符写入文件时,可以直接用FIleWriter进行操作,同样的在外面可以套上BufferedWriter进行使用。
BufferedWriter writer = new BufferedWriter(new FileWriter(""));
但是Writer有一个BufferedWriter的加强类(可以这么理解)-PrintWriter,一般情况下推荐使用PrintWriter对外进行输出,他和BufferedWriter相比较来说,具有几个优点。
-
PrintWriter的print、println方法可以接受任意类型的参数,而BufferedWriter的write方法只能接受字符、字符数组和字符串。
-
PrintWriter的println方法自动添加换行,BufferedWriter需要显示调用newLine方法。
-
PrintWriter的构造方法更广,可通过指定参数,实现自动刷新缓存(autoflush),而BufferedWriter需要通过flush方法来进行刷新。
-
同时PrintWriter在过程中不会抛出异常,如果关心异常,则要用checkError()来进行查看
五、总结
上面就是常见流的四大基类以及各自的子类,下面写几个对于流的一些日常使用例子。
案例1:通过oss的sdk拿到byte字节流之后,要在页面上进行内容的加载(txt为文档)。
StringBulider sb = new StringBuilder(); // 声明好最后返回的字符串,先用StringBuilder类型
byte[] bytes = new byte[8096]; //这里new一个字节数组模拟从oss上拿到数组
InputStream input = new ByteArrayInputeStream(bytes); //将字节数字转成字节输入流。
Reader reader = new InputStreadmReader(input,"UTF-8"); //将字节输入流转成字符输入流,字符格式使用utf-8
BufferedReader br = new BufferReader(reader); //套上缓冲流
String line = ""; //每次读到的字符
whiel((line = reader.readLine()) != null) { //每次去读文件的一行
sb.append(line).append("\n"); //将读到的一行内容给sb加上去,并且加换行符。
}
复制代码
最后将sb.toString进行返回就可以了,前端可以用pre标签直接接收以保持在后端已经设定好的格式内容。
案例2:写的一个将流进行字符转换的工具类。一开始代码是这样写的。
InputeStream in = System.in;
StringBulid sb = new StringBuild;
byte[] bytes = new byte[256];
int len = 0;
while((len = in.read(bytes)) != -1) {
sb.append(new String(bytes, 0, len));
}
复制代码
最后把sb.toString进行return就结束,小伙伴们看着有啥问题没?其实逻辑没错啊,这样写也没错啊,但是!!!但是日常使用中偶尔会有几个乱码出现,我就没想明白啊,字符集的问题吧,系统默认字符集给的是utf-8啊,不应该有乱码啊,而且偶尔蹦出来几个字是乱码,这是什么鬼,后来还是被被人一语道破,卧槽,Java中的字符集为utf-8的汉字是占3个字节,如果字数比较多的话,每次到最后取的字节就取不完整,就可能造成乱码问题,经过修复后代码如下。
InputeStream in = System.in;
ByteArrayOutputstream bos= new ByteArratOutputStream();
byte[] bytes = new byte[256];
int len = 0;
while((len = in.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
复制代码
因为每次都是将取出来的字节都存放到字节数组里,所以即使这一次取的将一个完整的汉字的3个字节打乱,也没有关系,会在下一次取数的时候给拼过来,只是将完整的字节输入流转换成了字节数组输出流,最后将new String(bos.toByteArray(),"UTF-8")进行返回就可以了。
作者:小年年
链接:https://juejin.im/post/5b58a5886fb9a04fb136eb44
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。