欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java读取C写的float,int和字符数组

程序员文章站 2022-04-25 15:49:49
...

0.README


本文提到了在用Java读取C写的字节文件时,因为两种语言的不同而遇到一些不兼容问题,包括float读取方式,int读取方式,char[]数组转字符串。


1.Java 读取C写的小端float


Intel主机中C写入的字节顺序是从低到高(左低到右高),而java.io.DataInputStream读取的数据是从高到低(左高到右低) 。前者称为LITTLE-ENDIAN(小字节序、低字节序),即低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。 后者对应的是:BIG-ENDIAN(大字节序、高字节序)。

因此我们需要调整字节的读取顺序。下面的例子中使用java.nio.ByteBuffer来处理。

// 读取C语言写的float
public static float readFloatFromC(DataInputStream dataInputStream){
    byte[] bytes = new byte[Float.SIZE/8];
    try {
        dataInputStream.read(bytes);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getFloat();
}


2.Java 读取C语言写的小端int

// read a integer from little-endian bytes
public static int readIntLe(byte[] bytes, int offset) {
    return (bytes[offset] & 0xff) | (bytes[offset + 1] & 0xff) << 8
            | (bytes[offset + 2] & 0xff) << 16 | (bytes[offset + 3] & 0xff) << 24;
}


3.Java 将C语言写的字符数组转换为String


首先,c语言的char只有一个字节,而java的char有2个字节,所以用java中的byte[]来存放从字节流中读取的C语言写的char[];然后用byte[]和字符集生成String;最后去掉C语言中的字符数组结束符‘\0’

// c写的字符数组转化为String
public static String byteArrayToString(byte[] bytes){
    String s = null;
    try {
        s = new String(bytes, "GBK");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return s.substring(0, s.indexOf(0));
}

4. Java 读取C++写的结构体文件

class PreSysSet
{
public:
    int first;
    int second;
    int third;
    bool fourth;
    int fifth;
}

Java 在读取C++的结构体时,主要的问题是要考虑到C++结构体保存时的存储结构,有两个规则(详细解释将参考资料4):

  1. 结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)
  2. 结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数

所以前4个i变量的偏移量分别是0、4、8、12,为了使结构体大小是int大小的整数倍,最后一个int变量在保存时会对齐偏移量,不是12 + 1 = 13,而是12 + 4 = 16,这样才能保证结构体大小为20。所以正确的 Java 读取方式如下:

    static class PreSysSet {
        int first;
        int second;
        int third;
        boolean fourth;
        int fifth;

        PreSysSet(DataInputStream in) {
            try {
                first = FileUtil.readIntFromC(in);
                second = FileUtil.readIntFromC(in);
                third = FileUtil.readIntFromC(in);
                fourth = in.readBoolean();
                in.skipBytes(3); // 为了对齐,所以产生了空位
                fifth = FileUtil.readIntFromC(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


参考文献


  1. reading C++ binary file in Java
  2. 大字节序(BigEndian)与小字节序(LittleEndian)
  3. Does Java read integers in little endian or big endian
  4. C/C++ sizeof函数解析——解决sizeof求结构体大小的问题
相关标签: float