为什么 BufferedReader 和 Scanner 无法识别换行符?

Why are BufferedReader and Scanner not identifying line breaks?

提问人:Cardinal System 提问时间:12/9/2022 最后编辑:Cardinal System 更新时间:12/9/2022 访问量:78

问:

我有一个程序,它通过串行端口从外部测试仪器读取数据。它使用 jSerialComm 通过串行端口进行通信。数据是行分隔的,因此我决定使用 BufferedReader 逐行读取它。不幸的是,当调用 readLine() 方法时,它会阻塞,直到读取超时。我尝试使用 Scanner,但在 nextLine() 阻止方面遇到了同样的问题。

SerialPort port = SerialPort.getCommPort("COM4");
port.openPort();
port.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 10000, 0);
BufferedReader reader = new BufferedReader(new InputStreamReader(port.getInputStream()));
while(true) {
    // This line blocks forever
    System.out.println(reader.readLine());
}

我认为可能使用了一个特殊字符来换行,所以我从流中读取原始字节并将它们打印到控制台:

int byteRead;
InputStream stream = port.getInputStream();
while ((byteRead = stream.read()) != -1) {
    System.out.write(byteRead);
    System.out.print(byteRead);
}

以下是输出的示例:

10M77E69A65N78 32=61 32654957.46654654 32H72R82351048N78
13
10S83T84D68 32D68E69V86 32=61 32755.46553553 32H72R82351048N78
13
10L76O79W87E69S83T84 32=61 32250654.46351048 32H72R82351048N78
13

您可以清楚地看到 ASCII 字符 13(回车符)被用作行分隔符,在 Java 中表示为 。JavaDoc for BufferedReader#readLine 说:\r

读取一行文本。一条线被视为被任何人终止 换行符 ('\n')、回车符 ('\r') 或回车符 紧随其后的是换行符。

这让我非常困惑,因为 BufferedReader 应该在这种情况下工作,但不能。我为一个以行分隔的阅读器起草了一个概念验证,该阅读器在换行符(或 ASCII 10)和回车符 (ASCII 13) 上中断,并修剪前导和尾随以及字符:\n\r\r\n

public class ScaleReader {

    private InputStream scaleInputStream;

    public ScaleReader(InputStream scaleInputStream) {
        this.scaleInputStream = scaleInputStream;
    }

    public String readLine() throws IOException {
        StringBuilder builder = new StringBuilder();

        int charByte = scaleInputStream.read();
        while (charByte != -1 && charByte == 13 || charByte == 10)
            charByte = scaleInputStream.read();

        if (charByte == -1)
            return null;

        builder.append((char) charByte);
        
        while (true) {
            charByte = scaleInputStream.read();
            if (charByte == -1 || charByte == 13 || charByte == 10)
                break;

            builder.append((char) charByte);
        }

        return builder.length() == 0 ? null : builder.toString();
    }

}

此代码按预期工作,并返回每次调用的正确数据。我不明白为什么 BufferedReader 在这种情况下不起作用,因为它显然应该将回车符识别为行终止符。readLine()

有解释吗?

Java java.util.scanner inputstream bufferedreader 换行符

评论

0赞 Jon Skeet 12/9/2022
您正在创建一个 没有指定字符编码 - 这意味着将使用平台默认值。您的平台默认编码是什么?您是否尝试过显式指定一个?InputStreamReader
0赞 Jon Skeet 12/9/2022
您可以尝试读取您的单个字符并将其打印出来 - 这可能有助于识别问题。BufferedReader
0赞 Cardinal System 12/9/2022
@JonSkeet我尝试读取一个字节,但该方法永远不会返回。BufferedReader#read
0赞 Jon Skeet 12/9/2022
这很奇怪。但是,好吧,接下来尝试不使用 BufferedReader,只需使用 InputStreamReader。(请注意,您不是从读取器读取字节,而是从字符读取 - 您需要区分两者。
0赞 Cardinal System 12/13/2022
@JonSkeet谢谢你为我做出这样的区分。我将来会记住这一点。我尝试只使用 InputStreamReader,但无济于事。

答: 暂无答案