Java 进程输入流错误?
嘿伙计们。所以这就是交易。我有一个运行 C++ 程序的 Java 程序。 C++ 进程只需通过一些指针转换调用 std::cout 上的 write 即可将一些双精度数发送到 Java 程序。 Java 程序使用 Process 的 getInputStream(),读取 8 个字节,并使用一些字节移位和 Double.longBitsToDouble() 将它们转换为 double。我已确保两个应用程序之间的类型大小和字节顺序匹配。现在,虽然这在大多数情况下都有效,但偶尔会出现错误。
我已将其中一个错误隔离为一个简单的字节序列,但我似乎无法正确传输该字节序列。查看以下片段:
#include <iostream>
int main(int argc, char** argv) {
long long l = 0x4048e398b90ae1b6;
char* ptr = (char*) &l;
std::cout.write(ptr, 8);
std::cout.flush();
// for (int i = 0; i < 8; ++i)
// std::cout.put(ptr[i]);
// std::cout.flush()
}
和 Java 应用程序:
public static void main(String[] argv) throws IOException {
Process p = Runtime.getRuntime().exec("prog.exe");
InputStream is = p.getInputStream();
for (int i = 0 ; i < 8; ++i) {
System.err.print(Long.toHexString(is.read()) + " ");
}
}
这些都是非常简单的示例,但它们可以演示我的问题。当我在 Windows 7 机器上运行它时。我得到以下 Java 输出:
b6 e1 d a b9 98 e3 48
预期的输出是
b6 e1 a b9 98 e3 48 40
不知何故,插入了一个额外的 0x0d 字节。然而,真正奇怪的是,如果在java应用程序中我们再读取一个字节(将8更改为9),我们会得到
b6 e1 d a b9 98 e3 48 40
这意味着InputStream实际上包含9个字节的数据,一旦删除了额外的0x0d,它就包含了正确的数据。
你们觉得怎么样?正如我之前提到的,这种情况并不经常发生,但一旦发生,那就是灾难性的。
提前致谢, 津基克
Hey guys. So here is the deal. I have a Java program run a C++ program. The C++ process sends some doubles to the Java program by simply calling write on std::cout with some pointer casting. The Java program uses Process's getInputStream(), reads in 8 bytes and converts them into a double using some byte shifting and Double.longBitsToDouble(). I have made sure that the type sizes as well as byte orders match up between the 2 applications. Now, while this works most of the time, every so often an error occurs.
I have isolated one of the errors to a simple sequence of bytes that I seem to be unable to transfer correctly. Check out the following snippets:
#include <iostream>
int main(int argc, char** argv) {
long long l = 0x4048e398b90ae1b6;
char* ptr = (char*) &l;
std::cout.write(ptr, 8);
std::cout.flush();
// for (int i = 0; i < 8; ++i)
// std::cout.put(ptr[i]);
// std::cout.flush()
}
And the Java app:
public static void main(String[] argv) throws IOException {
Process p = Runtime.getRuntime().exec("prog.exe");
InputStream is = p.getInputStream();
for (int i = 0 ; i < 8; ++i) {
System.err.print(Long.toHexString(is.read()) + " ");
}
}
These are pretty simple examples but they server to demonstrate my problem. When I run this on my Windows 7 machine. I get the following Java output:
b6 e1 d a b9 98 e3 48
The expected output is
b6 e1 a b9 98 e3 48 40
Somehow, an extra 0x0d byte is inserted. However, what is really weird is that if inside the java app we read one more byte (change the 8 to a 9), we get
b6 e1 d a b9 98 e3 48 40
This means that the InputStream actually contained 9 bytes of data and once that extra 0x0d is removed it contains the correct data.
What do you guys think? As I mentioned before, this doesn't happen often but when it does, it is disastrous.
Thanks in advance,
zienkikk
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
C++ 正在将 0x0A(即 \n)转换为 0x0d0a(即 \r\n)。有一种方法可以阻止它这样做,但无法帮助您了解它是什么。我自己不会将 iostream 用于二进制数据,我可能只会使用 write() 或 fwrite()。
C++ is translating 0x0A, which is \n, to 0x0d0a, which is \r\n. There's a method to stop it doing that, can't help you with what it is. I wouldn't use iostreams for binary data myself, I would probably just use write() or fwrite().
在我看来,您的 Windows shell 将 UNIX 样式行终止符 LF ( 0xA ) 转换为 Windows 行终止符 CRLF ( 0xD OxA )。
由于这个特殊原因,通常不建议将二进制数据写入程序输出流。将长数据转换为文本,然后在 Java 端解析它。
Looks to me like your Windows shell converts UNIX style line terminator LF ( 0xA ) to Windows Line Terminator CRLF( 0xD OxA ).
Generally it is not advisable to write binary data to the program output stream for this particular reason. Convert your long data to text and then parse it on a Java side.
cout
默认情况下以文本模式打开,我想说的是,0xa(换行)字符在输出预处理期间被转换为
序列。我认为不可能可靠地将二进制数据写入
cout
(请参阅 此处),所以我会将您所需的输出转换为文本,然后在输入端(Java)进行反序列化。cout
is by default opened in text mode, what I would say is happening is that the 0xa (linefeed) character is getting converted to a<CRLF>
sequence during output preprocessing.I don't think it's possible to reliably write binary data to
cout
(see here for example), so I would convert your desired output into text, and then deserialize on the input side (Java).