最近上傳阿里雲的時候同一個文件上傳兩個服務地址,第一個文件讀取以后第二個再去讀取就拿不到了。代碼如下:
//內網上傳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); }