怎么重复使用inputStream?

简介: 怎么重复使用inputStream?

引语:

    之前做项目的时候遇到一个问题,就是从网络中读取的图片要上传到oss,而且要对图片进行裁剪和压缩,其中上传和裁剪都要使用到图片的inputStream,
又因为inputstream不能重复读,导致裁剪是成功的,而上传是失败的.我们今天就提供两种方法来解决,inputStream不能重复读的问题.

问题分析:

inputStream的内部有个pos指针,当读取的时候指针会不断的移动,当移动到末尾的时候,就无法再次读取了.
我们写个简单的例子来看下:

    String text = "测试inputStream内容";
    InputStream inputStream = new ByteArrayInputStream(text.getBytes());
    byte[] readArray = new byte[inputStream.available()];
    int readCount1 = inputStream.read(readArray);
    System.out.println("读取了" + readCount1 + "个字节");

    byte[] readArray2 = new byte[inputStream.available()];
    int readCount2 = inputStream.read(readArray2);
    System.out.println("读取了" + readCount2 + "个字节");
    /**
    *  执行结果是
    *  读取了23个字节
    *  读取了-1个字节
    */

从执行结果可以看出确实inputstream的设计是只能读取一次.
注意: 这里稍微提一下inputStream.available()这个方法,本地的文件可以直接知道文件的大小,但是如果是网络中的数据,这个方法最好不要用,因为传输的时候不是连续的,数据的大小会读取不准

问题解决:

那么我们实际项目中应该怎么解决呢?总不能就真的只使用一次inputSteam吧.我们来看解决方法:
方法一:
使用ByteArrayOutputStream来缓存字节,然后每次读取从缓存的ByteArrayOutputStream中拿取.
很自然的想到把inputStream的缓存起来(当然不一定说是要放在ByteArrayOutputStream,其他的方式也可以,都是缓存起来的思路,实现方式有很多种,这种比较方便)

       String text = "测试inputStream内容";
       InputStream rawInputStream = new ByteArrayInputStream(text.getBytes());
       ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
       byte[] buffer = new byte[1024];
       int len;
       while ((len = rawInputStream.read(buffer)) > -1) {
           outputStream.write(buffer, 0, len);
       }
       outputStream.flush();
       InputStream in1 = new ByteArrayInputStream(outputStream.toByteArray());
       InputStream in2 = new ByteArrayInputStream(outputStream.toByteArray());
       int readCount1 = in1.read(buffer);
       int readCount2 = in2.read(buffer);
       System.out.println("读取了" + readCount1 + "个字节");
       System.out.println("读取了" + readCount2 + "个字节");
       /**
       *  执行结果是
       *  读取了23个字节
       *  读取了23个字节
       *

这里是先将inputStream的数据读取到output中,然后要反复使用inputStream中的内容的时候,我们将output中的数据取出(很神奇的设定,output可以反复取,input只能读一次)

方法二:
其实inputStream中有操作指针的方法,mark和reset,听名字就知道是标记和重置.在使用inputSteam前我们标记下inputStream指针的位置,读取完之后,重置,然后就可以反复使用了.我们看代码:

      String text = "测试inputStream内容";
      InputStream rawInputStream = new ByteArrayInputStream(text.getBytes());
      byte[] readArray = new byte[1024];
      rawInputStream.mark(0);
      int readCount1 = rawInputStream.read(readArray);
      rawInputStream.reset();
      int readCount2 = rawInputStream.read(readArray);
      System.out.println("读取了" + readCount1 + "个字节");
      System.out.println("读取了" + readCount2 + "个字节");

总结:

1.inputStream只能读取一次,也就是说只能调用read()或者其他的带参数的read()方法一次,在下次调用读取出来是-1,做项目的时候不要忘记这一点了,可能会导致有些坑出现;
2.可以使用缓存或者mark/reset方法来重复使用inputStream,这里要注意的是如果inputStream如果内容很多,缓存不是一个好办法,因为在使用完之前会占用大量的内存(我遇到过这样的,上传很多图片然后还有缓存,导致内存不够就一直fullGC,然后cpu先爆了);
3.还有一个小点就是别忘了关闭使用完的inputStream/outputSteam.

相关文章
|
3月前
|
Java 数据处理 开发者
Java IO流专家级教程:深入理解InputStream/OutputStream和Reader/Writer的内部机制
【6月更文挑战第26天】Java IO流涉及字节流(InputStream/OutputStream)和字符流(Reader/Writer),用于高效处理数据输入输出。InputStream/OutputStream处理二进制数据,常使用缓冲提升性能;Reader/Writer处理文本,关注字符编码转换。两者都有阻塞IO操作,但Java NIO支持非阻塞。示例代码展示了如何使用FileInputStream/FileOutputStream和FileReader/FileWriter读写文件。理解这些流的内部机制有助于优化代码性能。
88 0
|
3月前
|
Java 开发者
Java IO流实战技巧:如何优化InputStream/OutputStream和Reader/Writer的使用?
【6月更文挑战第26天】Java IO流优化涉及缓冲、资源管理、字符编码和流式处理。使用Buffered流提高读写效率,如`BufferedInputStream`和`BufferedReader`。确保资源关闭使用try-with-resources,如`try (InputStream is = ...) {...}`。处理文本时指定编码,如`InputStreamReader(is, StandardCharsets.UTF_8)`防止乱码。流式处理大文件,分块读写避免内存溢出,以减少内存占用。这些技巧能提升程序性能和健壮性。
144 0
|
4月前
|
Java 对象存储
Java解决InputStream流重复使用问题【100%解决】
Java解决InputStream流重复使用问题【100%解决】
|
Java
Java字节流有无缓冲流以及读取方式不同的所对应的时间(四种)
Java字节流有无缓冲流以及读取方式不同的所对应的时间(四种)
77 1
|
存储 编解码 缓存
InputStream、OutputStream、Reader、Writer的基本概念和使用方法
InputStream、OutputStream、Reader、Writer的基本概念和使用方法
127 0
|
存储 缓存 Java
【Java I/O 流】文件字节输入输出流:FileInputStream & FileOutputStream(文件读写案例)
本篇文章主要讲述“文件字节输入流”和“文件字节输出流”两个类的使用,并列举了一些案例,帮助学习。
226 0
|
存储 缓存 Java
【Java I/O 流】字节输入输出流:InputStream & OutputStream
本篇介绍字节输入输出流,它们是所有字节流的超类,提供了一些常用方法,我们一起看一下。
69 0
|
存储 缓存 Java
【Java I/O 流】字符输入输出流:Reader 和 Writer
前面我们已经学会了字节流的使用,本篇开始介绍字符流。字符输入输出流是所有字符流的超类,学会了它们的方法,也基本上掌握了其子类的使用了。
118 0
|
缓存 Java
【Java】文件操作篇(三)字符输入流、字符输出流及常用子类
文章目录 写在前面 1 FileReader与FileWriter 1.1 文件字符流体系概述 1.2 FileReader构造方法与相关方法摘要 1.3 FileWriter构造方法与相关方法摘要 2 案例实操 2.1 FileReader案例 2.2 FileWriter案例 3 处理流 3.1 BufferedReader介绍及使用案例 3.2 BufferedWriter介绍及使用案例 3.3 缓存文件拷贝
【Java】文件操作篇(三)字符输入流、字符输出流及常用子类
|
Java 程序员
JAVA:文本文件读写使用Reader/Writer,二进制文件使用InputStream/OutputStream
JAVA:文本文件读写使用Reader/Writer,二进制文件使用InputStream/OutputStream
79 0