InputStream为什么不能被重复读取?

最近上传阿里云的时候同一个文件上传两个服务地址,第一个文件读取以后第二个再去读取就拿不到了。代码如下:

   //内网上传OSS获取key值
        String ossKey = OSSClientUtil.getOSSURL(endpoint, accessKeyId, accessKeySecret, bucketName, key, inputStream);
        //外网上传OSS获取key值
        String outOssLink = OSSClientUtil.getOutOSSLink(outEndpoint, outAccessKeyId, outAccessKeySecret, outBucketName, key,
                inputStream); 

导致第二次上传失败。

Java中的Inputstream是不能重复读取的。
但是有没有想过,InputStream为什么不能重复读呢?
其实要回答“为什么”这个问题很简单,就是人家接口就是这么设计的,不能重复读。
所以今天要讨论的问题更像是:Java的InputStream为什么要设计为不能重复读?
关于InputStream为什么不能重复读取,网上也各有说法:
有的同学说:
“InputStream就类比成一个杯子,杯子里的水就像InputStream里的数据,你把杯子里的水拿出来了,杯子的水就没有了,InputStream也是同样的道理。”
比喻的非常好,让我们从直观上认识了InputStream为什么不能重复被读。
也有的同学从更深的代码角度去分析:
“在InputStream读取的时候,会有一个pos指针,他指示每次读取之后下一次要读取的起始位置,当读到最后一个字符的时候,pos指针不会重置。”
说的也有道理,就是说InputStream的读取是单向的。但是并不是所有的InputStream实现类都是这样的实现方式。

Java 的List内部是使用数组实现的,遍历的时候也有一个pos指针。但是没有说List遍历一个第二次遍历就没有了。第二次遍历是创建新的Iterator,所以pos也回到了数组起始位置。对于某些InputStream当然可以也这么做。例如:ByteArrayInputStream
ByteArrayInputStream就是将一个Java的byte数组保存到对象里,然后读取的时候遍历该byte数组。

更改以后的代码如下:

public class InputStreamFactory {

    private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    private byte[]                buffer                = new byte[1024];

    public InputStreamFactory(InputStream input) throws IOException {
        int len;
        while ((len = input.read(buffer)) > -1) {
            byteArrayOutputStream.write(buffer, 0, len);
        }
        byteArrayOutputStream.flush();
    }

    public InputStream newInputStream() {
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

}

更改代码:

  InputStreamFactory inputStreamFactory = null;
        try {
            inputStreamFactory = new InputStreamFactory(inputStream);
            //内网上传OSS获取key值
            String ossKey = OSSClientUtil.getOSSURL(endpoint, accessKeyId, accessKeySecret, bucketName, key,
                    inputStreamFactory.newInputStream());
            //外网上传OSS获取key值
            String outOssLink = OSSClientUtil.getOutOSSLink(outEndpoint, outAccessKeyId, outAccessKeySecret, outBucketName,
                    key, inputStreamFactory.newInputStream());
        } catch (IOException e) {
            log.info("读取文件流失败", e);
        }

  

posted @ 2018-12-21 15:53  jason.bai  阅读(2190)  评论(0编辑  收藏  举报