I want to create a file that contains exactly 8 bytes representing an unsigned long number. The file is created with Java and then read by C++. This is how Java creates the file:
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());
}
}
}
And this is how C++ reads it:
#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;
}
The expected output is 12345
, but instead I get 4120793659044003840
.
I am not sure if I did it wrong in Java or C++. Or both. What should I have done?
Java writes long
in "network order", which is big endian. C++ reads in hardware order, which in your case is little endian.
It does not mean, however, that your C++ program should flip the bytes for conversion, because in this case it would fail on hardware with big endian order.
C provides a special group of functions for platform-independent conversion of data to and from network order. You need to use htonll
function, which converts eight bytes in network order to your hardware order.
Java writes the long
as bytes encoded in big endian, guaranteed.
C++ reads the bytes, and on your machine (assumed to be Intel x86) they are interpreted in little endian as an integer. (Big endian on Motorola 68k and others.)
One solution to your problem is to manually reconstruct the integer in C++ in a portable way:
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;
Side note: Your Java code can be simplified:
DataOutputStream out = new DataOutputStream(new FileOutputStream("myFile"));
try {
out.writeLong(12345); // 8 bytes in big endian
} finally {
out.close();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With