为何BufferedReader与Scanner无法识别串口数据中的换行符?
串口读取中BufferedReader无法识别\r作为行分隔符的原因
问题背景
我用jSerialComm开发了读取外部测试仪器串口数据的程序,数据按行分隔。最初用BufferedReader的readLine()逐行读取,但调用后会一直阻塞直到超时;换成Scanner的nextLine()也遇到同样问题。
排查后发现仪器以ASCII 13(回车符\r)作为行分隔符,虽然BufferedReader的JavaDoc说明它能识别\r作为行终止符,但实际就是不生效。后来自行编写了ScaleReader类,能正确识别\n和\r,调用其readLine()可正常获取数据,想知道BufferedReader失效的原因。
相关代码
原BufferedReader实现
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) { // 该行一直阻塞 System.out.println(reader.readLine()); }
原始字节读取代码
int byteRead; InputStream stream = port.getInputStream(); while ((byteRead = stream.read()) != -1) { System.out.write(byteRead); System.out.print(byteRead); }
自定义ScaleReader类
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()确实会把\r视为行终止符,但它的处理逻辑存在特殊判断:
- 当读到
\r时,会继续读取下一个字节,判断是否是\n:- 如果是
\n,就将这两个字符作为行终止符,返回之前的内容; - 如果不是
\n(比如串口数据流到\r就结束,没有后续字节),它会持续阻塞等待,直到有新字节输入或者触发读取超时。
- 如果是
而你的自定义ScaleReader类读到\r就直接终止读取并返回内容,不会等待后续字节,因此能正常获取单条数据。串口场景下仪器发送完\r后不会再发送额外字节,BufferedReader的等待逻辑就会导致你遇到的阻塞问题。
内容的提问来源于stack exchange,提问作者Cardinal System
相关产品推荐
相关产品推荐

