Java:BufferedReader是否可以读取多行?

5
我正在使用Java Socket编写程序。 我可以向客户端发送命令,并从客户端发送到服务器。 为了读取命令,我使用BufferedReader。 要编写它们,使用PrintWriter。但是现在我想通过套接字传输文件(而不仅仅是创建第二个连接)
首先,我要通过输出流写入文件包含的字节数。例如40000字节。 因此,我通过套接字写入数字40000,但连接的另一侧读取78
所以我想:通过调用readLine() BufferedReader读取的不仅仅是一行,因此我会从文件数据中丢失一些字节。 因为它们在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");
}

以下是解决方案:
感谢James的建议
我认为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");
}

马特因。

嗯,为什么另一边读作78?你是什么意思? - notnoop
1
使用DataInputStream代替BufferedReader。 - james
1
另外,通常可用的方法是无用的,请勿使用。 - james
我遇到了与DataInputStream相同的问题。 - Martijn Courteaux
@james:你好,我通过你的建议解决了问题。请发布真正的问题,这样我就可以接受你的答案了。我会编辑我的问题,这样每个人都可以看到我所做的事情。 - Martijn Courteaux
1
请注意我的关于“available”的注释。使用File.length()。 - james
4个回答

4

我不确定我是否理解了你的解释。

然而,是的 - 你无法真正控制BufferedReader读取多少内容。这种阅读器的重点在于它乐观地阅读底层资源的块,以满足其缓冲区的需求。因此,当您首次调用readLine时,它会发现其内部缓冲区没有足够的内容来服务您的请求,并且会从底层源中读取任意数量的字节到其缓冲区中,这通常比您刚才要求的要多得多。一旦缓冲区被填充,它将返回缓冲内容中的行。

因此,一旦您在BufferedReader中包装输入流,您应该确保只通过同一个缓冲读取器读取该流。如果不这样做,您将最终丢失数据(因为一些字节已被使用并现在位于BufferedReader的缓存中等待提供)。


没错。我的待办清单上有一项是一个Reader/InputStream组合,它可以缓冲字符并传递字节。至少从2003年以来就一直在那里了。 :) - Bombe
这听起来不错。但是我检查了从BufferedReader.read();读取的源代码。每个\n字符都将被跳过。这意味着他将跳过每10个字节(10 ==(int)'\n')。 - Martijn Courteaux

1

DataInputStream 是您最可能想要使用的。此外,不要使用 available() 方法,因为它通常是无用的。


0

只是一次猜测 – 40000 在二进制中是1001110001000000。现在,这里的前七位是1001110,即78。这意味着,您正在写入2个字节的信息,但读取7个字节。


40000(十进制)是 9C40(十六进制)。 - Bombe
好的,我明白了,但我的意思是前七位是78(已更正)。 - laginimaineb

0

BufferedReader假定它是唯一从底层输入流读取的对象。

它的目的是最小化从底层流中读取的次数(这很昂贵,因为它们可能会委托得非常深入)。为此,它保持一个缓冲区,在单个调用底层流时通过读取尽可能多的字节来填充它。

所以,是的,你的诊断是准确的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接