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

时间:2023-03-09 04:17:29
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);
}