Почему InputStream.read () генерирует исключение «Тайм-аут чтения», если объект inputStream ранее был помещен в BufferedReader? - PullRequest
0 голосов
/ 11 июля 2019

У меня есть объект inputStream, который поступает из сокета.

Этот поток может быть простым текстом или содержать двоичные данные.У него есть простой текстовый префикс, который говорит мне, какой тип данных он имеет.Я использую 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, он больше не может использоваться напрямую?

1 Ответ

1 голос
/ 11 июля 2019

A BufferedReader читает из Reader и сохраняет данные в буфере для последующего чтения для использования. Он читает столько, сколько может за один раз, и каждый раз, когда буфер очищается, он читает больше в буфер.

Время ожидания вашего двоичного файла истекло, потому что BufferedReader уже прочитал байты, которые вы пытаетесь прочитать.

Для определения типа потока требуется всего 4 байта. Использование Reader для этих 4 байтов является излишним. Сначала считайте байты непосредственно из InputStream, затем создайте Reader только для данных text, например:

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