当 inputStream 对象先前已包装在 BufferedReader 中时,为什么 InputStream.read() 抛出 "Read timed out" 异常?

Why does InputStream.read() throw "Read timed out" exception when the inputStream object has previously been wrapped in a BufferedReader?

我有一个来自套接字的 inputStream 对象。

这个流可以是纯文本,也可以包含二进制数据。它有一个纯文本 "prefix" 告诉我它有哪种类型的数据。我使用 BufferedReader 读取该前缀。然后,如果数据类型是纯文本,我继续使用 BufferedReader 读取其余部分,效果很好。

问题是当我切换回使用 InputStream 时如果前缀指示非文本数据。流似乎在某处丢失了,我得到的是 java.net.SocketTimeoutException: Read timed out

代码是这样的:

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
}

这是不允许的吗?一旦instream被包裹在BufferedReader中,就不能直接使用了吗?

一个BufferedReader从一个Reader中读取数据并将数据存储在缓冲区中以供后续读取使用。它一次读取尽可能多的内容,每次缓冲区清空时,它都会向缓冲区中读取更多内容。

您的二进制读取超时,因为 BufferedReader 已经读取了您尝试读取的字节。

检测流类型只需要4个字节。对这 4 个字节使用 Reader 是多余的。首先直接从InputStream中读取字节,然后只为text数据创建一个Reader,例如:

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);
}

或者,考虑使用 BufferedInputStream 进行套接字读取,并根据需要在其上添加其他 类,例如:

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);
}