【问题标题】:Serialize in Java and read in C++在 Java 中序列化并在 C++ 中读取
【发布时间】:2021-04-07 22:36:42
【问题描述】:

我正在尝试序列化 Java 对象,使其内容可以被现有的 reader.cc 模块读取,该模块当前读取用 C++ 生成的二进制文件。

以下是来自 reader.cc 的 sn-p,它读取 3 个变量 (name_len, fname, and feature_names_count):

uint32_t name_len;
in.read((char *)&name_len, sizeof(uint32_t));          

char *fname = new char[name_len + 1];
in.read(fname, sizeof(char) * name_len);           
fname[name_len] = '\0';

uint32_t feature_names_count;
in.read((char *)&feature_names_count, sizeof(uint32_t));  

这就是我在 Java 中所做的事情,其中​​我正在序列化的 3 个变量(并从 myObject 读取)的类型为 int, String, int(我尝试了每个注释的方法):

    private static void createBinaryFile(TestClassToSerialize myObject) throws IOException {
        File myFile = new File(PATHNAME);
        myFile.createNewFile();
        writeObjectToFile(new FileOutputStream(myFile), myObject);
    }

    private static void writeObjectToFile(FileOutputStream fos, TestClassToSerialize myObject) throws IOException {
        fos.write(intToByteArray(myObject.getNameLen()));
        fos.write(myObject.getFname().getBytes());
        fos.write(intToByteArray(myObject.getFeatureNamesCount()));
        fos.close();
    }

    public static byte[] intToByteArray(int data) {
        return Ints.toByteArray(data);
    }
//    public static final byte[] intToByteArray(int value) {
//        return new byte[] {
//                (byte)(value >>> 24),
//                (byte)(value >>> 16),
//                (byte)(value >>> 8),
//                (byte)value};
//    }

//    public static byte[] intToByteArray(int data) {
//        byte[] result = new byte[4];
//        result[0] = (byte) ((data & 0xFF000000) >> 24);
//        result[1] = (byte) ((data & 0x00FF0000) >> 16);
//        result[2] = (byte) ((data & 0x0000FF00) >> 8);
//        result[3] = (byte) ((data & 0x000000FF) >> 0);
//        return result;
//    }

这些是从 reader.cc 读取的值:251658240、_Z9test_loopPii、4294967295; 这些是我要序列化的值:15, _Z9test_loopPii, 4;

我也尝试将数字存储为long,然后使用以下方法将其序列化为字节:

public static byte[] longToBytes(long x) {
        ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
        buffer.putLong(x);
        return Arrays.copyOfRange(buffer.array(), 0, 4);
    }

但是,当我在 C++ 中反序列化时,我得到的值与从其他代码(序列化整数的代码)中得到的值相同。

我无法更改 C++ 代码,但我可以在 Java 代码中做任何我想做的事情,甚至可以将不同格式的数据存储在 myObject 中。

你有什么建议吗?

以下是包含上述代码的存储库的链接(它们都是 OSS),以防某些上下文可能有所帮助:reader.ccJava code

【问题讨论】:

  • 您是否尝试过使用十六进制编辑器以十六进制转储二进制文件的内容,并准确了解 Java 代码如何将数据写入其中,并将其与您的 C++ 代码所期望的进行比较阅读?如果你这样做了,你会在几秒钟内得到答案。
  • @RichardCritten 我愿意,但我不想修改 C++ 系统。
  • “它不起作用”信息不足。在不修改 C++ 的情况下,您至少可以调试它并查看它读取的值与您期望的值?
  • unit32_t 是 32 位的。你写的是 64 位(long)。
  • @NicolaAmadio 看起来你现在搞乱了字节顺序 - 大端与小端。 (基本上写int的时候要反转字节数组的字节)

标签: java c++ serialization binary


【解决方案1】:

关键是正确序列化 int/long。

我选择使用 int,因为它有 32 个字节,与阅读器端的 uint32_t 相同。获取其中的字节并将其反转就足够了(因为大端与小端,感谢 Johannes Kuhn 的建议)。

方法如下:

public static byte[] intToByteArray(int data) {
        byte[] bytes = Ints.toByteArray(data);
        ArrayUtils.reverse(bytes);
        return bytes;
    }

我使用 Guava 从整数 (Ints.toByteArray) 中获取字节,但还有其他方法可以做到这一点,比如问题中注释掉的那些(除此之外,只需反转字节数组)。

【讨论】:

  • 除了反转数组之外,另一种方法是修改 intToByteArray 以按正确的顺序生成数组。
猜你喜欢
  • 2012-03-10
  • 1970-01-01
  • 2012-10-24
  • 2011-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-14
  • 1970-01-01
相关资源
最近更新 更多