In Java data is stored in Bigbig-Endian endian format (also called network order), that is, all data is represented sequentially starting from the most significant bit (MSB) to the least significant. Prior to jdk JDK 1.4, custom methods had to be defined to be compatible with Littlelittle-Endian endian systems that use the reverse byte order. Handling byte order related issues is critical when data is to be exchanged in a networked environment that consists of machines varying in Endiannessendianness. Failure to handle such cases can cause misinterpretations and unexpected program behavior.
...
The java.io.DataInputStream
class defines read methods (readByte, readShort, readInt, readLong, readFloat and readDouble
) and the corresponding write methods. All these methods work with Bigbig-Endian endian data only. The usage use of these methods can be unsafe while interfacing with traditional languages such as C /or C++, that do not provide any guarantees on Endiannessendianness. This noncompliant example shows such a discrepancy.
Code Block | ||
---|---|---|
| ||
DataInputStream dis = new DataInputStream( new FileInputStream("data.txt")); // Little-Endianendian data might be read as Bigbig-Endianendian int serialNumber = dis.readInt(); |
...
This compliant solution wraps the byte array containing the integer bytes read-in into a ByteBuffer
and sets the byte order to Littlelittle-Endianendian. The result is stored in the integer serialNumber
.
Code Block | ||
---|---|---|
| ||
DataInputStream dis = new DataInputStream( new FileInputStream("data.txt")); byte[] buffer= new byte[4]; int bytesRead = dis.read(buffer); // Bytes will beare read into buffer int serialNumber = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt(); |
...
Assuming that an integer value is to be read from the file, read and write methods can be defined for handling Littlelittle-Endian endian data. The readLittleEndianInteger
method reads data into a byte buffer and then pieces together the integer in the right order. Long
values can be handled by defining a byte buffer of size 8
. The writeLittleEndianInteger
method obtains bytes by repeatedly casting the integer so that the MSB most significant byte is extracted on successive right shifts.
Code Block | ||
---|---|---|
| ||
// read method public static int readLittleEndianInteger(InputStream ips) throws IOException { int result; byte[] buffer = new byte[4]; int check = ips.read(buffer); if (check != 4) throw new IOException("Unexpected End of Stream"); result = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]; return result; } // write method public static void writeLittleEndianInteger(int i, OutputStream ops) throws IOException { int result; byte[] buffer = new byte[4]; buffer[0] = (byte) i; buffer[1] = (byte) (i >> 8); buffer[2] = (byte) (i >> 16); buffer[3] = (byte) (i >> 24); ops.write(buffer); } |
Compliant Solution (3)
In jdk JDK 1.5+, the Integer.reverseBytes()
method can be used to reverse the order of the bytes constituting the integer. Note that there is no such method for float
and double
values.
...
Reading and writing data without considering Endianness endianness may lead to serious misinterpretations about magnitude and sign, alike.
...