我想知道
InputStream
是否为空,但不使用方法read()
。有没有办法在不读取的情况下知道它是否为空?
不,你不能。
InputStream
设计用于使用远程资源,因此在您实际读取它之前,您无法知道它是否存在。
但是,您也许可以使用
java.io.PushbackInputStream
,它允许您从流中读取内容以查看其中是否有内容,然后将其“推回”流中(这不是它真正的工作方式,但这就是它对客户端代码的行为方式)。
inputstream.available()
。它不会告诉您它是否为空,但它可以指示您是否有数据可供读取。
根据使用 PushbackInputStream 的建议,您将在这里找到一个示例实现:
/**
* @author Lorber Sebastien <i>([email protected])</i>
*/
public class NonEmptyInputStream extends FilterInputStream {
/**
* Once this stream has been created, do not consume the original InputStream
* because there will be one missing byte...
* @param originalInputStream
* @throws IOException
* @throws EmptyInputStreamException
*/
public NonEmptyInputStream(InputStream originalInputStream) throws IOException, EmptyInputStreamException {
super( checkStreamIsNotEmpty(originalInputStream) );
}
/**
* Permits to check the InputStream is empty or not
* Please note that only the returned InputStream must be consummed.
*
* see:
* http://stackoverflow.com/questions/1524299/how-can-i-check-if-an-inputstream-is-empty-without-reading-from-it
*
* @param inputStream
* @return
*/
private static InputStream checkStreamIsNotEmpty(InputStream inputStream) throws IOException, EmptyInputStreamException {
Preconditions.checkArgument(inputStream != null,"The InputStream is mandatory");
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
int b;
b = pushbackInputStream.read();
if ( b == -1 ) {
throw new EmptyInputStreamException("No byte can be read from stream " + inputStream);
}
pushbackInputStream.unread(b);
return pushbackInputStream;
}
public static class EmptyInputStreamException extends RuntimeException {
public EmptyInputStreamException(String message) {
super(message);
}
}
}
以下是一些通过的测试:
@Test(expected = EmptyInputStreamException.class)
public void test_check_empty_input_stream_raises_exception_for_empty_stream() throws IOException {
InputStream emptyStream = new ByteArrayInputStream(new byte[0]);
new NonEmptyInputStream(emptyStream);
}
@Test
public void test_check_empty_input_stream_ok_for_non_empty_stream_and_returned_stream_can_be_consummed_fully() throws IOException {
String streamContent = "HELLooooô wörld";
InputStream inputStream = IOUtils.toInputStream(streamContent, StandardCharsets.UTF_8);
inputStream = new NonEmptyInputStream(inputStream);
assertThat(IOUtils.toString(inputStream,StandardCharsets.UTF_8)).isEqualTo(streamContent);
}
如果您使用的
InputStream
支持标记/重置支持,您还可以尝试读取流的第一个字节,然后将其重置到原始位置:
input.mark(1);
final int bytesRead = input.read(new byte[1]);
input.reset();
if (bytesRead != -1) {
//stream not empty
} else {
//stream empty
}
如果您无法控制所使用的
InputStream
类型,则可以使用 markSupported()
方法来检查标记/重置是否适用于流,然后回退到 available()
方法或 java.io.PushbackInputStream
其他方法。
available()
方法询问流在您调用它时是否有任何可用数据。但是,不能保证该函数适用于所有类型的输入流。这意味着您无法使用 available()
来确定对
read()
的调用是否会实际阻塞。
inputStreamReader.ready() 来找出答案?
import java.io.InputStreamReader;
/// ...
InputStreamReader reader = new InputStreamReader(inputStream);
if (reader.ready()) {
// do something
}
// ...
您可以使用 mark(int readlimit) 方法标记此输入流中的当前位置。
reset() 方法将此流重新定位到上次在此输入流上调用 mark 方法时的位置。
在使用标记和重置之前,您需要测试您正在读取的输入流是否支持这些操作。您可以使用 markSupported 来做到这一点。
mark方法接受一个限制(整数),它表示要提前读取的最大字节数。如果您阅读超过此限制,则无法返回此标记。
要将此功能应用于此用例,我们需要将位置标记为 0,然后读取输入流。之后我们需要重置输入流,输入流将恢复为原始流。
if (inputStream.markSupported()) {
inputStream.mark(0);
if (inputStream.read() != -1) {
inputStream.reset();
} else {
//Inputstream is empty
}
}
这里如果输入流为空,则 read() 方法将返回 -1。
在进行业务处理之前需要检查HttpInputStream是否为空的场景,我们会读取InputStream并将其转换为String来检查是否为空:
InputStream entityStream = requestContext.getEntityStream();
String requestString = new BufferedReader(
new InputStreamReader(entityStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining());
之后,我们将实体流重置为原始流:
InputStream inputStream = new ByteArrayInputStream(requestString.getBytes(StandardCharsets.UTF_8));
//reset the entity stream based on the original stream
requestContext.setEntityStream(inputStream);
这种方法帮助我们处理需要在继续进一步处理之前验证输入流是否为空的情况。
public void run() {
byte[] buffer = new byte[256];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
break;
}
}
}