转载

I/O流

I/O流按说是Java中的一个基础,学是大家都学过,整体是有大概印象的,但从开始我就没有太理清各个流之间的关系和用法,日常用的时候大致能写,有一些复杂的、记不清的都是从网上进行百度,大致看懂之后Ctrl+C与Ctrl+V进行修修改改,懂那个意思了但是没多久就会忘了,这几天通过看书和阅读大家的blog,自己更清晰了一些,整理了一下。

整个大的分类,不二话,还是那四个,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 字节缓冲输出流
OutputStream 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(""));
复制代码

四、Writer

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相比较来说,具有几个优点。

  1. PrintWriter的print、println方法可以接受任意类型的参数,而BufferedWriter的write方法只能接受字符、字符数组和字符串。

  2. PrintWriter的println方法自动添加换行,BufferedWriter需要显示调用newLine方法。

  3. PrintWriter的构造方法更广,可通过指定参数,实现自动刷新缓存(autoflush),而BufferedWriter需要通过flush方法来进行刷新。

  4. 同时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")进行返回就可以了。

以上是对I/O使用的一些心得体会,和大家分享,希望能够指出不足,互相交流。

原文  https://juejin.im/post/5b58a5886fb9a04fb136eb44
正文到此结束
Loading...