У меня есть объект 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
, его больше нельзя будет использовать напрямую?
@JBNizet, это имеет смысл. Не стесняйтесь сделать свой комментарий ответом, чтобы я мог его принять. Спасибо!
@JamesKPolk спасибо. Я задавался вопросом, был ли это правильный английский. "буферы" - правильный глагол?
@JBNizet: Да, buffers
правильно, но в некотором смысле bufferizes
более выразительно, если не совсем правильно. Это могло бы сделать лучшую работу, чтобы сделать вашу точку зрения.
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);
}
Буферизованный ридер, как следует из его названия и поясняется в его javadoc, буферизует. Когда вы попросите его прочитать два символа, он прочитает, скажем, 4096 и сохранит их в буфере, чтобы ускорить чтение в будущем. Поэтому, если вы вернетесь к обернутому потоку для чтения, вы прочитаете байты, расположенные после байтов первых 4096 символов.