Java: BufferedReader читает больше, чем строку? - PullRequest
5 голосов
/ 02 декабря 2009

Я делаю программу на Java с сокетами. Я могу отправлять команды клиенту и от клиента серверу. Для чтения команд я использую BufferedReader. Чтобы написать их, PrintWriter Но теперь я хочу передать файл через , который сокет (а не просто создать второе соединение) .
Сначала я пишу в выходной поток, как много байтов в файле. Например 40000 байт. Таким образом, я пишу число 40000 через сокет, но другая сторона соединения читает 78.

Итак, я подумал: BufferedReader читает больше, чем просто строку (вызывая readLine()) , и таким образом я теряю несколько байтов из файла-данных. Потому что они в буфере от BufferedReader.
Таким образом, число 78 является байтом файла, который я хочу передать.

Правильно ли это мышление или нет. Если да, то как решить эту проблему.
Надеюсь, я хорошо объяснил.


Вот мой код, но мой язык по умолчанию - голландский. Поэтому некоторые имена переменных могут звучать странно.

public void flushStreamToStream(InputStream is, OutputStream os, boolean closeIn, boolean closeOut) throws IOException {
    byte[] buffer = new byte[BUFFERSIZE];
    int bytesRead;
    if ((!closeOut) && closeIn) { // To Socket from File
        action = "Upload";
        os.write(is.available()); // Here I write 400000
        max = is.available();
        System.out.println("Bytes to send: " + max);
        while ((bytesRead = is.read(buffer)) != -1) {
            startTiming(); // Two lines to compute the speed
            os.write(buffer, 0, bytesRead);
            stopTiming(); // Speed compution
            process += bytesRead;
        }
        os.flush();
        is.close();
        return;
    }
    if ((!closeIn) && closeOut) { // To File from Socket
        action = "Download";
        int bytesToRead = -1;
        bytesToRead = is.read(); // Here he reads 78.
        System.out.println("Bytes to read: " + bytesToRead);
        max = bytesToRead;
        int nextBufferSize;
        while ((nextBufferSize = Math.min(BUFFERSIZE, bytesToRead)) > 0) {
            startTiming();
            bytesRead = is.read(buffer, 0, nextBufferSize);
            bytesToRead -= bytesRead;
            process += nextBufferSize;
            os.write(buffer, 0, bytesRead);
            stopTiming();
        }
        os.flush();
        os.close();
        return;
    }
    throw new IllegalArgumentException("The only two boolean combinations are: closeOut == false && closeIn == true AND closeOut == true && closeIn == false");
}

Вот решение:
Благодаря предложению Джеймса
Я думаю laginimaineb Ответ был частью решения.

Прочитайте команды.

DataInputStream in = new DataInputStream(is); // Originally a BufferedReader
// Read the request line
String str;
while ((str = in.readLine()) != null) {
    if (str.trim().equals("")) {
       continue;
    }
    handleSocketInput(str);
}

Теперь flushStreamToStream:

public void flushStreamToStream(InputStream is, OutputStream os, boolean closeIn, boolean closeOut) throws IOException {
    byte[] buffer = new byte[BUFFERSIZE];
    int bytesRead;
    if ((!closeOut) && closeIn) { // To Socket from File
        action = "Upload";
        DataOutputStream dos = new DataOutputStream(os);
        dos.writeInt(is.available());

        max = is.available();
        System.out.println("Bytes to send: " + max);
        while ((bytesRead = is.read(buffer)) != -1) {
            startTiming();
            dos.write(buffer, 0, bytesRead);
            stopTiming();
            process += bytesRead;
        }
        os.flush();
        is.close();
        return;
    }
    if ((!closeIn) && closeOut) { // To File from Socket
        action = "Download";
        DataInputStream dis = new DataInputStream(is);
        int bytesToRead = dis.readInt();
        System.out.println("Bytes to read: " + bytesToRead);
        max = bytesToRead;
        int nextBufferSize;
        while ((nextBufferSize = Math.min(BUFFERSIZE, bytesToRead)) > 0) {
            startTiming();
            bytesRead = is.read(buffer, 0, nextBufferSize);
            bytesToRead -= bytesRead;
            process += nextBufferSize;
            os.write(buffer, 0, bytesRead);
            stopTiming();
        }
        os.flush();
        os.close();
        return;
    }
    throw new IllegalArgumentException("The only two boolean combinations are: closeOut == false && closeIn == true AND closeOut == true && closeIn == false");
}

Мартейн.

Ответы [ 4 ]

4 голосов
/ 02 декабря 2009

Я не уверен, что следовал вашему объяснению.

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

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

1 голос
/ 02 декабря 2009

DataInputStream, скорее всего, то, что вы хотите использовать. Кроме того, не используйте метод available (), так как он обычно бесполезен.

0 голосов
/ 02 декабря 2009

BufferedReader предполагает, что это единственное чтение из основного входного потока.

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

Так что да, ваш диагноз точен.

0 голосов
/ 02 декабря 2009

Просто дикий удар здесь - 40000 - это 1001110001000000 в двоичном виде. Итак, первые семь битов здесь - 1001110, то есть 78. То есть вы записываете 2 байта информации, но читаете семь битов.

...