我有一个程序将通过 System.in 从外部源接收信息。有两种输入模式:行模式和原始模式。在行模式下,输入只是一系列 UTF-8 字符串,每个字符串都以换行符结束。在线路模式下的某个时刻,我会收到通知说我将要接收 N 字节的原始数据。那时输入切换到原始模式,我收到了 N 个字节的原始二进制数据,它们不是有效的 UTF-8 字符。在此之后,它返回到线路模式。
有没有办法在读取字符串和读取原始数据之间轻松切换?我唯一的想法是逐字节读取 InputStream 并在进行时转换为字符。有没有办法用多种类型的输入流包装 System.in?我觉得从两个不同的包装器中读取会导致问题。
(固定)更新:
我尝试了 parsifal 的建议,但遇到了问题。为了模拟切换输入模式,我修改了我的测试工具。(我意识到我的另一个进程最终也需要以这种方式输出。)我不知道问题是由发送端还是接收端引起的。当我在输出模式之间切换时,它似乎没有正确读取字节。此外,它总是出现相同的字节值。以下是一些代码摘录:
FIX: 问题是显然你不能太快地从 OutputStreamWriter 切换到 OutputStream。我在发送原始字节之前添加了一个 1ms 的睡眠命令,问题就解决了!
测试线束:
Process p = processList.get(pubName); //Stored list of started Processes
OutputStream o = p.getOutputStream(); //Returns OutputStream which feeds into stdin
out = new OutputStreamWriter(runPublisher.getOutputStream());
byte[] payload = new byte[25];
out.write("\nPAYLOAD\nRAW\n"); // "RAW\n" signals raw mode
out.write(String.valueOf(payload.length) + "\n");
out.flush();
Thread.sleep(1); //This fixed the problem I was having.
System.out.println(Arrays.toString(payload));
o.write(payload);
o.flush();
客户:
InputStreamReader inReader = new InputStreamReader(System.in);
while(true){
try{
if((chIn = inReader.read())!= -1){
if(chIn == (int)'\n'){
if(rawMode){
if(strIn.equals("ENDRAW"))
rawMode = false;
else{
System.out.println(strIn);
//Exception on next line
int rawSize = Integer.parseInt(strIn);
payload = new byte[rawSize];
int t = System.in.read(payload);
System.out.println("Read " + t + " bytes");
System.out.print(Arrays.toString(payload));
}
}else if(strIn.startsWith("RAW")){
rawMode = true;
}else {
// Do other things
}
strIn = "";
}else
strIn += (char)chIn;
}else
break;
}catch(IOException e){break;}
}
输出(在添加 Sleep 语句之前)如下所示:
测试线束:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
客户端:
25
读取 9 个字节
[83, 72, 85, 84, 68, 79, 87, 78, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0]
Exception in thread "main" java.lang.NumberFormatException: For input string: "
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:470)
at java.lang.Integer.parseInt(Integer.java:514)
at myClass.handleCommand(myClass.java:249)