我正在处理一些Java代码,其中有一个InputStream,我读取了一次,然后我需要以相同的方法再次读取它。
问题是我需要将其位置重置为开头才能读取两次。
我找到了解决这个问题的黑客式解决方案:
is.mark(Integer.MAX_VALUE);
//Read the InputStream is fully
// { ... }
try
{
is.reset();
}
catch (IOException e)
{
e.printStackTrace();
}
此解决方案是否会导致一些未经检查的行为?或者它会在它的愚蠢中工作?
如前所述,您不能保证,因为mark()
不需要报告它是否成功。要获得保证,您必须首先调用 markSupported(),并且它必须返回 true
。
同样如所写,指定的读取限制非常危险。如果您碰巧使用在内存中缓冲的流,它可能会分配 2GB 缓冲区。另一方面,如果您碰巧正在使用 FileInputStream
,您没事。
更好的方法是使用带有显式缓冲区的BufferedInputStream
。
这取决于 InputStream 实现。你也可以考虑如果使用byte[]是否会更好。最简单的方法是使用 Apache commons-io:
byte[] bytes = IOUtils.toByteArray(inputSream);
您无法可靠地执行此操作;某些InputStream
(例如连接到终端或插座的)不支持mark
和reset
(请参阅markSupported
)。如果确实必须遍历数据两次,则需要将其读入自己的缓冲区。
与其尝试重置InputStream
不如将其加载到缓冲区中,例如StringBuilder
,或者如果它是二进制数据流,则ByteArrayOutputStream
。然后,您可以根据需要多次处理方法中的缓冲区。
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int read = 0;
byte[] buff = new byte[1024];
while ((read = inStream.read(buff)) != -1) {
bos.write(buff, 0, read);
}
byte[] streamData = bos.toByteArray();
对我来说,最简单的解决方案是传递可以从中获取输入流的对象,然后再次获取它。就我而言,它来自一个ContentResolver
.