C&;中的fwrite();Java中的readInt()的结尾不同
本机代码: 使用fwrite()写入数字27。C&;中的fwrite();Java中的readInt()的结尾不同,java,android,c,endianness,datainputstream,Java,Android,C,Endianness,Datainputstream,本机代码: 使用fwrite()写入数字27。 int main() { int a = 27; FILE *fp; fp = fopen("/data/tmp.log", "w"); if (!fp) return -errno; fwrite(&a, 4, 1, fp); fclose(); return 0; } 使用DataInputStream.readInt()读回数据(27): public int readIntDataInput
int main()
{
int a = 27;
FILE *fp;
fp = fopen("/data/tmp.log", "w");
if (!fp)
return -errno;
fwrite(&a, 4, 1, fp);
fclose();
return 0;
}
使用DataInputStream.readInt()读回数据(27):
public int readIntDataInputStream(void)
{
String filePath = "/data/tmp.log";
InputStream is = null;
DataInputStream dis = null;
int k;
is = new FileInputStream(filePath);
dis = new DataInputStream(is);
k = dis.readInt();
Log.i(TAG, "Size : " + k);
return 0;
}
O/p
十六进制是0x1b000000
0x1b
是27
。但是readInt()将数据读取为big-endian,而我的原生编码将数据写入little-endian。因此,我得到的不是0x0000001b
,而是0x1000000
我的理解正确吗?以前有人遇到过这个问题吗?来自Javadoc for
readInt()
:
此方法适用于读取接口DataOutput
如果您想读取由C程序编写的内容,您必须使用java.nio
中的工具自己进行字节交换。我从来没有这样做过,但我相信你会将数据读入一个ByteBuffer
,将缓冲区的顺序设置为ByteOrder.LITTLE_ENDIAN
,然后在ByteBuffer
上创建一个IntBuffer
视图,如果你有一个值数组,或者只使用ByteBuffer\getInt()
除此之外,我同意@EJP的观点,即数据的外部格式应该是big-endian,以实现最大的兼容性。您的代码中存在多个问题:
- 假设
的大小为int
,这不一定是真的,因为您想要处理32位int,所以应该使用4
或int32\u t
uint32\u t
- 为了可靠地写入二进制数据,必须更多地以二进制方式打开文件。上述代码将在Windows上失败,以获得不那么琐碎的输出。使用
fopen(“/data/tmp.log”,“wb”)
- 你必须处理endianness。您正在使用该文件在可能具有不同本机端号和/或端号特定API的不同平台之间交换数据。Java似乎使用big-endian,也称为网络字节顺序,因此您应该使用
实用程序函数在C平台上转换值。这不太可能对PC端的性能产生重大影响,因为此函数通常是内联扩展的,可能是作为一条指令,而且大部分时间都将花费在等待I/O上hton32()
#include <endian.h>
#include <stdint.h>
#include <stdio.h>
int main(void) {
uint32_t a = hton32(27);
FILE *fp = fopen("/data/tmp.log", "wb");
if (!fp) {
return errno;
}
fwrite(&a, sizeof a, 1, fp);
fclose();
return 0;
}
#包括
#包括
#包括
内部主(空){
uint32_t a=hton32(27);
文件*fp=fopen(“/data/tmp.log”,“wb”);
如果(!fp){
返回errno;
}
fwrite(&a,大小为a,1,fp);
fclose();
返回0;
}
是的,你是对的。C将以CPU的尾数写,这对于x86处理器来说是小尾数。他总是读大端文。解决方案:决定你的文件应该有哪一个尾端,并确保两者都相应地起作用。更重要的是,决定文件应该是big-endian,这使得它可以移植并与Java兼容,并相应地调整C代码。在这个C代码中你需要的是inta=htonl(27)代码>谢谢@Andreas。我有大量的数据要写。如何在C中有效地处理这个问题?@EJP实际上我有大量的数据,这些数据是从本机代码写入文件并从Java应用程序读取的。。是否有推荐的方法?另请参见ByteBuffer
has a以int
的形式读取给定尾数下的4个字节IntBuffer
视图仅在所有数据都是int
时有用,例如,如果它是int[]
。您好,谢谢您的回答。关于第1点和第2点,我知道这些事情。另外,disz只是一个测试代码。第1点->我把它当作4个字节,因为前面提到过,java的readInt()将读取4个字节。2->我为unix系统工作。在Unix系统中,fopen中的“b”没有任何意义。在手册页中,“这是为了与C89完全兼容,没有效果;在所有符合POSIX标准的系统(包括Linux)上,'b'被忽略。”但是,这些都是使程序看起来更简洁的优点。谢谢。@mk..:我知道发布的代码只是一个快速而肮脏的测试。我总是试图提供一个详细的答案,不仅是OP,而且其他读者看到所有潜在的问题“wb”
在大多数Unix平台上严格等同于“w”
,但使用b
并没有什么坏处,更明显的是“/data/tmp.log”
是一个二进制文件,其名称并不意味着它int
在绝大多数Unix系统上是32位长的,但是long
(java中为64位)的大小在不同的ABI上有所不同,即使在同一主机上(32位模式与64位模式)。优雅应该成为第二天性。
#include <endian.h>
#include <stdint.h>
#include <stdio.h>
int main(void) {
uint32_t a = hton32(27);
FILE *fp = fopen("/data/tmp.log", "wb");
if (!fp) {
return errno;
}
fwrite(&a, sizeof a, 1, fp);
fclose();
return 0;
}