在文件中从 Java 写入一个 Long 并在 C++ 中读取它

Writing a Long from Java in a file and reading it in C++

我想创建一个包含 8 个字节的文件,表示一个无符号长整数。该文件使用 Java 创建,然后由 C++ 读取。这是 Java 创建文件的方式:

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;

public class Writer {

    public static void main(String[] args) throws Exception {

        ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
        buffer.putLong(12345);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        stream.write(buffer.array());
        try (FileOutputStream outputStream = new FileOutputStream("myFile")) {
            outputStream.write(stream.toByteArray());
        }

    }

}

这就是 C++ 读取它的方式:

#include <iostream>
#include <vector>
#include <fstream>
#include <stdio.h>

using namespace std;

// I use this to get each byte from a file
static std::vector<char> ReadAllBytes(char const* filename) {
    std::ifstream ifs(filename, ios::binary|ios::ate);
    std::ifstream::pos_type pos = ifs.tellg();

    std::vector<char>  result(pos);

    ifs.seekg(0, ios::beg);
    ifs.read(&result[0], pos);

    return result;
}


int main (int argc, char* argv[]) {
    std::vector<char> bytes = ReadAllBytes("myFile");
    std::vector<char>::iterator it = bytes.begin();

    char longBytes[8];
    std::copy(&(*it), &(*it) + 8, longBytes);
    unsigned long value = *((unsigned long*)longBytes);

    std::cout << "Size: " << value;
}

预期的输出是 12345,但我得到的是 4120793659044003840

我不确定我是不是在Java或C++中做错了。或两者。我应该怎么做?

Java 将 long 写为以大端编码的字节,保证。

C++ 读取字节,并在您的机器(假定为 Intel x86)上将它们以小端字节序解释为整数。 (摩托罗拉 68k 和其他计算机上的大端。)

您的问题的一个解决方案是以可移植的方式在 C++ 中手动重建整数:

uint64_t value =
    (uint64_t)(b[0] & 0xFF) << 56 |
    (uint64_t)(b[1] & 0xFF) << 48 |
    (uint64_t)(b[2] & 0xFF) << 40 |
    (uint64_t)(b[3] & 0xFF) << 32 |
    (uint64_t)(b[4] & 0xFF) << 24 |
    (uint64_t)(b[5] & 0xFF) << 16 |
    (uint64_t)(b[6] & 0xFF) <<  8 |
    (uint64_t)(b[7] & 0xFF) <<  0;

旁注:您的 Java 代码可以简化:

DataOutputStream out = new DataOutputStream(new FileOutputStream("myFile"));
try {
    out.writeLong(12345);  // 8 bytes in big endian
} finally {
    out.close();
}

Java在"network order"中写入long,也就是big endian。 C++ 按硬件顺序读取,在您的情况下是小端。

但是,这并不意味着您的 C++ 程序应该翻转字节以进行转换,因为在这种情况下,它会在具有大端顺序的硬件上失败。

C 提供了一组特殊的函数,用于独立于平台的数据与网络顺序之间的转换。您需要使用 htonll 函数,它将网络顺序中的八个字节转换为您的硬件顺序。