兩次讀取流
回答
您可以使用org.apache.commons.io.IOUtils.copy
的InputStream的內容複製到一個字節數組,然後使用一個ByteArrayInputStream字節數組反覆讀。例如: -
ByteArrayOutputStream baos = new ByteArrayOutputStream();
org.apache.commons.io.IOUtils.copy(in, baos);
byte[] bytes = baos.toByteArray();
// either
while (needToReadAgain) {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
yourReadMethodHere(bais);
}
// or
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
while (needToReadAgain) {
bais.reset();
yourReadMethodHere(bais);
}
根據InputStream的來源,您可能無法重置它。您可以使用markSupported()
來檢查是否支持mark()
和reset()
。
如果是,您可以在InputStream上調用reset()
返回到開頭。如果不是,則需要再次從源讀取InputStream。
的InputStream不支持 '標記' - 你可以調用上的IS標誌但它什麼都不做。同樣,在一個IS上調用reset會引發異常。 – ayahuasca 2017-09-05 13:18:31
如果您使用的是InputStream
的實現,您可以檢查InputStream#markSupported()
的結果,告訴您是否可以使用方法mark()
/reset()
。
如果您可以在讀取時標記流,然後請撥打reset()
以開始。
如果你不能,你將不得不再次打開一個流。
另一種解決方案是將InputStream轉換爲字節數組,然後根據需要隨時迭代數組。您可以在這篇文章中找到若干解決方案Convert InputStream to byte array in Java使用第三方庫或不使用。注意,如果讀取的內容太大,您可能會遇到一些內存問題。
最後,如果你需要的是讀取圖像,然後使用:
BufferedImage image = ImageIO.read(new URL("http://www.example.com/images/toto.jpg"));
使用ImageIO#read(java.net.URL)
,您還可以使用緩存。
當使用'ImageIO#read(java.net.URL)'時,出現一個警告詞:一些網絡服務器和CDN可能拒絕裸機調用(即沒有使服務器認爲調用來自web瀏覽器的用戶代理) ImageIO的#read'。在這種情況下,使用'ImageUI.read(InputStream)'使用'URLConnection.openConnection()'將用戶代理設置爲該連接+將會大部分時間都會發揮作用。 – 2017-08-10 19:12:12
'InputStream'不是接口 – Brice 2017-11-30 12:58:04
@Brice的確,感謝您指出這一點! – 2017-11-30 15:00:13
將輸入流轉換爲字節,然後將其傳遞給savefile函數,並將其彙編到輸入流中。 此外,在原有功能的使用字節用於其他任務
我說這個不好主意,由此產生的數組可能會很大,並會搶奪內存設備。 – 2012-03-09 20:30:54
如果使用標記的InputStream
支持,那麼你可以mark()
你的InputStream和再reset()
它。如果您InputStrem
不支持標記,那麼你可以使用類java.io.BufferedInputStream
,這樣你就可以嵌入BufferedInputStream
內的流這樣
InputStream bufferdInputStream = new BufferedInputStream(yourInputStream);
bufferdInputStream.mark(some_value);
//read your bufferdInputStream
bufferdInputStream.reset();
//read it again
你可以用PushbackInputStream包裹輸入流。 PushbackInputStream允許未讀(「回寫」),這已經讀取的字節,所以你可以這樣做:
public class StreamTest {
public static void main(String[] args) throws IOException {
byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
InputStream originalStream = new ByteArrayInputStream(bytes);
byte[] readBytes = getBytes(originalStream, 3);
printBytes(readBytes); // prints: 1 2 3
readBytes = getBytes(originalStream, 3);
printBytes(readBytes); // prints: 4 5 6
// now let's wrap it with PushBackInputStream
originalStream = new ByteArrayInputStream(bytes);
InputStream wrappedStream = new PushbackInputStream(originalStream, 10); // 10 means that maximnum 10 characters can be "written back" to the stream
readBytes = getBytes(wrappedStream, 3);
printBytes(readBytes); // prints 1 2 3
((PushbackInputStream) wrappedStream).unread(readBytes, 0, readBytes.length);
readBytes = getBytes(wrappedStream, 3);
printBytes(readBytes); // prints 1 2 3
}
private static byte[] getBytes(InputStream is, int howManyBytes) throws IOException {
System.out.print("Reading stream: ");
byte[] buf = new byte[howManyBytes];
int next = 0;
for (int i = 0; i < howManyBytes; i++) {
next = is.read();
if (next > 0) {
buf[i] = (byte) next;
}
}
return buf;
}
private static void printBytes(byte[] buffer) throws IOException {
System.out.print("Reading stream: ");
for (int i = 0; i < buffer.length; i++) {
System.out.print(buffer[i] + " ");
}
System.out.println();
}
}
請注意字節是PushbackInputStream商店內部緩衝區,所以它確實創造了一個緩衝保存字節「回寫」的內存。
瞭解這種方法,我們可以進一步將其與FilterInputStream結合起來。FilterInputStream將原始輸入流存儲爲委託。這允許創建新的類別定義,其自動允許「未讀」原始數據。此類的定義如下:
public class TryReadInputStream extends FilterInputStream {
private final int maxPushbackBufferSize;
/**
* Creates a <code>FilterInputStream</code>
* by assigning the argument <code>in</code>
* to the field <code>this.in</code> so as
* to remember it for later use.
*
* @param in the underlying input stream, or <code>null</code> if
* this instance is to be created without an underlying stream.
*/
public TryReadInputStream(InputStream in, int maxPushbackBufferSize) {
super(new PushbackInputStream(in, maxPushbackBufferSize));
this.maxPushbackBufferSize = maxPushbackBufferSize;
}
/**
* Reads from input stream the <code>length</code> of bytes to given buffer. The read bytes are still avilable
* in the stream
*
* @param buffer the destination buffer to which read the data
* @param offset the start offset in the destination <code>buffer</code>
* @aram length how many bytes to read from the stream to buff. Length needs to be less than
* <code>maxPushbackBufferSize</code> or IOException will be thrown
*
* @return number of bytes read
* @throws java.io.IOException in case length is
*/
public int tryRead(byte[] buffer, int offset, int length) throws IOException {
validateMaxLength(length);
// NOTE: below reading byte by byte instead of "int bytesRead = is.read(firstBytes, 0, maxBytesOfResponseToLog);"
// because read() guarantees to read a byte
int bytesRead = 0;
int nextByte = 0;
for (int i = 0; (i < length) && (nextByte >= 0); i++) {
nextByte = read();
if (nextByte >= 0) {
buffer[offset + bytesRead++] = (byte) nextByte;
}
}
if (bytesRead > 0) {
((PushbackInputStream) in).unread(buffer, offset, bytesRead);
}
return bytesRead;
}
public byte[] tryRead(int maxBytesToRead) throws IOException {
validateMaxLength(maxBytesToRead);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); // as ByteArrayOutputStream to dynamically allocate internal bytes array instead of allocating possibly large buffer (if maxBytesToRead is large)
// NOTE: below reading byte by byte instead of "int bytesRead = is.read(firstBytes, 0, maxBytesOfResponseToLog);"
// because read() guarantees to read a byte
int nextByte = 0;
for (int i = 0; (i < maxBytesToRead) && (nextByte >= 0); i++) {
nextByte = read();
if (nextByte >= 0) {
baos.write((byte) nextByte);
}
}
byte[] buffer = baos.toByteArray();
if (buffer.length > 0) {
((PushbackInputStream) in).unread(buffer, 0, buffer.length);
}
return buffer;
}
private void validateMaxLength(int length) throws IOException {
if (length > maxPushbackBufferSize) {
throw new IOException(
"Trying to read more bytes than maxBytesToRead. Max bytes: " + maxPushbackBufferSize + ". Trying to read: " +
length);
}
}
}
該類有兩種方法。一個用於讀入現有緩衝區(定義類似於調用InputStream類的public int read(byte b[], int off, int len)
)。第二個返回新的緩衝區(如果讀取的緩衝區的大小未知,這可能會更有效)。
現在,讓我們在行動中看到我們班:
public class StreamTest2 {
public static void main(String[] args) throws IOException {
byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
InputStream originalStream = new ByteArrayInputStream(bytes);
byte[] readBytes = getBytes(originalStream, 3);
printBytes(readBytes); // prints: 1 2 3
readBytes = getBytes(originalStream, 3);
printBytes(readBytes); // prints: 4 5 6
// now let's use our TryReadInputStream
originalStream = new ByteArrayInputStream(bytes);
InputStream wrappedStream = new TryReadInputStream(originalStream, 10);
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3); // NOTE: no manual call to "unread"(!) because TryReadInputStream handles this internally
printBytes(readBytes); // prints 1 2 3
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3);
printBytes(readBytes); // prints 1 2 3
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3);
printBytes(readBytes); // prints 1 2 3
// we can also call normal read which will actually read the bytes without "writing them back"
readBytes = getBytes(wrappedStream, 3);
printBytes(readBytes); // prints 1 2 3
readBytes = getBytes(wrappedStream, 3);
printBytes(readBytes); // prints 4 5 6
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3); // now we can try read next bytes
printBytes(readBytes); // prints 7 8 9
readBytes = ((TryReadInputStream) wrappedStream).tryRead(3);
printBytes(readBytes); // prints 7 8 9
}
}
如何:
if (stream.markSupported() == false) {
// lets replace the stream object
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(stream, baos);
stream.close();
stream = new ByteArrayInputStream(baos.toByteArray());
// now the stream should support 'mark' and 'reset'
}
- 1. 讀取流兩次?
- 2. 從FileStream讀取兩次
- 3. 如何在C#中兩次讀取Http響應流?
- 4. Spark SQL read.json讀取JSON輸入兩次
- 5. 如何讓cin讀取兩次?
- 6. StreamSocket在城域讀取兩次
- 7. 如何讀取文件兩次
- 8. 試圖避免兩次讀取文件
- 9. Fortran read()讀取最後一行兩次?
- 10. for循環讀取前執行兩次
- 11. 一次從文件中讀取兩行
- 12. 讀取WCF消息正文兩次 - 「消息無法讀取」
- 13. 兩次連續的套接字讀取,二次讀取不起作用
- 14. 讀取流
- 15. 讀通過scanf的一個線,但它會讀取兩次
- 16. Python:讀取輸出腳本兩次,並寫入兩列csv
- 17. iPhone:讀取gzipped流
- 18. 如何讀取相同的輸入流兩次,而沒有輸入流停止工作
- 19. 多次讀取SerialDataPort
- 20. 一次讀取inputStream
- 21. 需要再次幫助從輸入流中讀取數據
- 22. 這個循環會多少次讀取輸入流?
- 23. 從c#中的相同流中讀取多次#
- 24. 如何從一個流中讀取並一次寫入多個?
- 25. 如何通過php讀取廣播流並再次將其流出
- 26. .Net從流中讀取流段
- 27. Zend_Http_Client - 從流中讀取?
- 28. 將NSMutableData讀取爲流
- 29. 從HttpResponseMessage.Content讀取流內容
- 30. java.io.IOException - IO流結束讀取
也許使用mark和reset – 2012-02-29 14:54:26