在文件中从 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
函数,它将网络顺序中的八个字节转换为您的硬件顺序。
我想创建一个包含 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
函数,它将网络顺序中的八个字节转换为您的硬件顺序。