Оставляет ли Java BufferedReader байты во внутреннем буфере после вызова readline ()? - PullRequest
0 голосов
/ 31 мая 2011

У меня проблема на моем сервере, после того, как я отправляю файл с X-байтами, я отправляю строку, сообщающую, что этот файл закончился, и приходит другой файл, например

FILE: a SIZE: Y\r\n
send Y bytes
FILE a FINISHED\r\n
FILE b SIZE: Z\r\n
send Z byes
FILE b FINISHED\r\n
FILES FINISHED\r\n

В моем клиенте он не получает должным образом. Я использую readline (), чтобы получить командные строки после чтения байтов Y или Z из сокета. С одним файлом он работает нормально, с несколькими файлами он работает редко (да, я не знаю, как он работал один или два раза)

Вот код, который я использую для передачи двоичного файла

public static void readInputStreamToFile(InputStream is, FileOutputStream fout,
        long size, int bufferSize) throws Exception
{
    byte[] buffer = new byte[bufferSize];
    long curRead = 0;
    long totalRead = 0;
    long sizeToRead = size;
    while(totalRead < sizeToRead)
    {
        if(totalRead + buffer.length <= sizeToRead)
        {
            curRead = is.read(buffer);
        }
        else
        {
            curRead = is.read(buffer, 0, (int)(sizeToRead - totalRead));
        }
        totalRead = totalRead + curRead;
        fout.write(buffer, 0, (int) curRead);
    }
}





public static void writeFileInputStreamToOutputStream(FileInputStream in, OutputStream out, int bufferSize) throws Exception
{
    byte[] buffer = new byte[bufferSize];
    int count = 0;
    while((count = in.read(buffer)) != -1)
    {
        out.write(buffer, 0, count);
    }
}

только для заметки, я мог бы решить заменить readline на этот код:

    ByteArrayOutputStream ba = new ByteArrayOutputStream();
    int ch;
    while(true)
    {
        ch = is.read();
        if(ch == -1)
            throw new IOException("Conecção finalizada");
        if(ch == 13)
        {
            ch = is.read();
            if(ch == 10)
                return new String(ba.toByteArray(), "ISO-8859-1");
            else
                ba.write(13);
        }
        ba.write(ch);
    }

PS: "is" - это мой поток ввода из socket: socket.getInputStream ();

до сих пор я не знаю, является ли это лучшей реализацией, я пытаюсь выяснить

Ответы [ 4 ]

5 голосов
/ 31 мая 2011

Здесь нет кодов readLine() в коде, но для ответа на ваш вопрос;Да, вызов BufferedReader.readLine() вполне может оставить вещи во внутреннем буфере.Он буферизует входные данные.

Если вы оберните один из своих InputStream в BufferedReader,, вы не сможете получить много нормального поведения, если будете читать из BufferedReader, а затем читать из InputStream.

Вы можете прочитать байты из вашего InputStream и проанализировать текстовую строку из этого, отыскивая пару \r\n байтов.Когда вы получили строку с надписью «ФАЙЛ: РАЗМЕР: Y \ r \ n», вы продолжаете как обычно, за исключением того, что буфер, который вы использовали для разбора строк, может содержать первые несколько байтов вашего файла, поэтому сначала запишите эти байты.

Или вы используете идею FTP и используете один поток TCP для команд и один поток TCP для фактической передачи, читая из потока команд с BufferedReader.readLine(), и читая данные, как вы уже делаете с InputStream.

2 голосов
/ 31 мая 2011

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

То, что у него есть метод readLine(), является просто хорошим бонусом, который легко становится возможным благодаря буферизации.

Возможно, вы захотите использовать DataInputStream (поверх BufferedInputStream) и его метод readLine(), если вам действительно нужно смешивать текстовые и двоичные данные по одному и тому же соединению - читать данные из того же DataInputStream. (Но позаботьтесь о кодировке здесь.)

0 голосов
/ 31 мая 2011

Полагаю, вы должны очистить выходной поток, чтобы убедиться, что все буферизованные байты правильно отправлены в поток.При закрытии потока также будет запущен этот процесс.

Javadocs для сброса говорит:

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

0 голосов
/ 31 мая 2011

Вызовите flush() в OutputStream после того, как вы написали данные, которые, как вы хотите быть уверены, были отправлены. По сути, в конце каждого файла вызывать flush().

...