两次读取流
回答
您可以使用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. 读取InMemoryUploadedFile两次
- 3. socket.readLine()读取两次
- 4. 读取file.inputstream两次
- 5. 从FileStream读取两次
- 6. LinkedList读取根值两次
- 7. HttpURLConnection读取InputStream两次
- 8. 流>>最后一行读两次
- 9. 如何两次或多次读取BufferedReader?
- 10. RedPark电缆readBytesAvailable每次读取两次
- 11. 为什么我无法读取Http请求输入流两次?
- 12. 如何在C#中两次读取Http响应流?
- 13. 读取一次流多消费者
- 14. BufferedReader流首次读取的垃圾
- 15. fscanf读取最后的整数两次
- 16. Mainform.cs读取例程超过两次
- 17. 无法读取使用两次QAxObject
- 18. 一次读取两行CSV(Java)
- 19. 一次从文件中读取两行
- 20. Spark SQL read.json读取JSON输入两次
- 21. 试图避免两次读取文件
- 22. StreamSocket在城域读取两次
- 23. 从ifstream读取两次的符号
- 24. Fortran read()读取最后一行两次?
- 25. 如何读取文件两次
- 26. 如何让cin读取两次?
- 27. for循环读取前执行两次
- 28. 读取WCF消息正文两次 - “消息无法读取”
- 29. 两次连续的套接字读取,二次读取不起作用
- 30. 读取流
也许使用mark和reset – 2012-02-29 14:54:26