Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
164 views
in Technique[技术] by (71.8m points)

Serialize in Java and read in C++

I am trying to serialize a Java object in such a way that its content can be read by an existing reader.cc module, which currently reads binaries generated in C++.

The following is a snippet from reader.cc, where it reads 3 variables (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] = '';

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

This is what I am doing in Java, where the 3 variables that I am serializing (and reading from myObject) are of type int, String, int (I tried each of the commented methods):

    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;
//    }

These are the values that are read from reader.cc: 251658240, _Z9test_loopPii, 4294967295; These are the values that I am instead serializing: 15, _Z9test_loopPii, 4;

I also tried storing the digits as long, and then using the following method to serialize it to bytes:

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

But, when I deserialize in C++, I get the same values that I get from the other code (the one that serilizes integers).

I can't change the C++ code, but I can do whatever I want in the Java one, even store data in different formats in myObject.

Do you have any suggestion?

Here are the links to the repositories containing the above-mentioned code (they are both OSS), in case some context might help: reader.cc, Java code.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The key was to serialize the int/long correctly.

I chose to use an int because it had 32 bytes, same as uint32_t on reader side. It was enough to take the bytes in it and reverse it (because of big endian vs little endian, thanks Johannes Kuhn for the suggestion).

Here's the method:

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

I used Guava to get bytes out of the integer (Ints.toByteArray), but there were also other ways to do this, like the ones commented out in the question (just reverse the bytes array in addition to that).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
...