java - Why does InputStream.read() throw "Read timed out" exception when the inputStream object has previously been wrapped in a BufferedReader?
问题描述
I have an inputStream object that comes from a socket.
This stream could be all plain text, or it could contain binary data. It has a plain text "prefix" that tells me which type of data it has. I use BufferedReader to read that prefix. Then, if the data type is plain text, I continue to use BufferedReader to read the rest which works just fine.
The problem is when I switch back to using InputStream if the prefix indicates non-text data. The stream seems to be lost somewhere, and I get a java.net.SocketTimeoutException: Read timed out
instead.
Code goes something like this:
InputStream instream = mysocket.getInputStream();
BufferedReader br = (new InputStreamReader(instream, "UTF-8")));
byte[] prefixArray = new byte[4];
br.read(prefixArray, 0, 4);
String prefix = new String(prefixArray);
if("text".equals(prefix)) {
// continue to use br.read() here, which works fine...
}else{
byte[] barray = new byte[arraysize]
instream.read(barray, 0, arraysize); // THROWS "Read timed out" exception
}
Is this simply not allowed? Once instream
is wrapped in a BufferedReader
, it can't be used directly any longer?
解决方案
A BufferedReader
reads from a Reader
and stores the data in a buffer for subsequent reads to use. It reads as much as it can at one time, and each time the buffer is emptied, it reads more into the buffer.
Your binary reads time out because the BufferedReader
has already read the bytes you are trying to read.
It takes only 4 bytes for you to detect the stream type. Using a Reader
for those 4 bytes is overkill. Read the bytes directly from the InputStream
first, then create a Reader
only for the text
data, eg:
InputStream instream = mysocket.getInputStream();
byte[] prefixArray = new byte[4];
int offset = 0;
int numread;
do
{
numread = instream.read(prefixArray, offset, 4-offset);
if (numread == -1) return;
offset += numread;
}
while (offset < 4);
String prefix = new String(prefixArray);
if ("text".equals(prefix))
{
BufferedReader br = new BufferedReader(new InputStreamReader(instream, "UTF-8"));
//...
}
else
{
byte[] barray = new byte[arraysize];
// consider using BufferedInputStream here ...
do
{
numread = instream.read(barray, 0, arraysize);
if (numread == -1) break;
//...
}
while (true);
}
Alternatively, consider using BufferedInputStream
for the socket reading, and add other classes on top of it as needed, eg:
InputStream instream = mysocket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(instream);
byte[] prefixArray = new byte[4];
DataInputStream dis = new DataInputStream(bis);
dis.readFully(prefixArray);
String prefix = new String(prefixArray);
if ("text".equals(prefix))
{
InputStreamReader isr = new InputStreamReader(bis, "UTF-8"));
//...
}
else
{
byte[] barray = new byte[arraysize];
do
{
numread = bis.read(barray, 0, arraysize);
if (numread == -1) break;
//...
}
while (true);
}
推荐阅读
- python - 自动电子邮件查找(Python、SMTP)
- python - AWS Lambda Python 处理程序 - dynamodb:NoVersionFound
- android - 如何用旋转的 webview 填充屏幕?
- c# - ReactiveUI WhenAnyValue ToPropertyEx 到一个可为空的小数
- html - 是否有快捷方式或扩展来预览 CSS 属性值并在 VSCode 中选择其中一个?
- c++ - 为什么 QGraphicsRectItem 对象无论显式提供的坐标如何都停留在坐标(0,0)?
- javascript - 如何根据 PHP 购物车值动态更改 paypal smartbutton 的价格?
- javascript - SPFx 1.4 和 React 15 的 React 组件交互的 Redux 替代方案 - 无 Hooks
- java - Spring webmvc 控制器接受 `.com/` 但在 url 中拒绝 `.com` 并抛出 406 错误
- node.js - 我在 docker 中运行一个 mongodb 实例。如何在我的 nodejs 应用程序中获取连接字符串以将其与 RoboT3 或猫鼬一起使用?