Universal Integer Reader/Writer
There are a wide variety of ways to read and write integers to a file. This code fragment enhances Java's RandomAccessFile to encompass a wider variety of methods, including 1, 2 and 4 byte integers, and both signed and unsigned values.
By default Java values are always signed values, and multi-byte values are always big-endian. In the real world, however, many times you will need to read or write to files with integer types that are unsigned, or little-endian. Here, I have expanded Java's RandomAccessFile to include a more universal file reading and writing mechanism. It's important to remember, though, that the data type may not be what you expect. For instance, reading a 1-byte integer, results in an int data type, not a byte. This is because Java can't express an unsigned byte using a byte type. There are similar type changes in 2 and 4 byte values as well.
public class KlangRAF extends RandomAccessFile {
public KlangRAF(String name, String mode) throws FileNotFoundException {
super(name, mode);
}
public KlangRAF(File file, String mode) throws FileNotFoundException {
super(file, mode);
}
/**
* Read a one-byte integer value.
*
* @param signed if true, value will be signed
* @return the one-byte value as an int
* @throws IOException if read error occurs
*/
public int read1ByteInt(boolean signed) throws IOException {
if (signed) {
return (int)this.readByte();
} else {
return this.readUnsignedByte();
}
}
/**
* Write a one-byte integer value. Will work correctly with either a signed or unsigned value.
*
* @param value the byte value to write
* @throws IOException if value is out of range or write error occurs
*/
public void write1ByteInt(int value) throws IOException {
if ((value 255)) {
throw new IOException("Int value is out of range");
}
if (value >= 128) {
value = value - 256;
}
this.writeByte(value);
}
/**
* Read a two-byte integer value.
*
* @param signed if true, value will be signed
* @param isBigEndian if true, value will be read as a big-endian value; false for small-endian
* @return the two-byte value as an int
* @throws IOException if read error occurs
*/
public int read2ByteInt(boolean signed, boolean isBigEndian) throws IOException {
if (signed) {
if (isBigEndian) {
return (int)this.readShort();
} else {
short val = this.readShort();
val = Short.reverseBytes(val);
return (int)val;
}
} else {
if (isBigEndian) {
short val = this.readShort();
int output = val & 0xffff;
return output;
} else {
short val = this.readShort();
val = Short.reverseBytes(val);
int output = val & 0xffff;
return output;
}
}
}
/**
* Write a 2-byte integer to a file
*
* @param value the value expressed as an integer
* @param signed whether the value should be written as a signed or unsigned value
* @param isBigEndian true if the value should be written as big-endian, false for small-endian
* @throws IOException if value is out of range, or a write error occurs
*/
public void write2ByteInt(int value, boolean signed, boolean isBigEndian) throws IOException {
if (signed) {
if ((value < -32768) || (value > 32767)) {
throw new IOException("Int value is out of range");
}
} else {
if ((value < 0) || (value > 65535)) {
throw new IOException("Int value is out of range");
}
}
if (signed) {
if (isBigEndian) {
this.writeShort(value);
return;
} else {
short output = Short.reverseBytes((short)value);
this.writeShort(output);
}
} else {
if (isBigEndian) {
short output = (short)(value & 0xffff);
this.writeShort(output);
} else {
short output = (short)(value & 0xffff);
output = Short.reverseBytes(output);
this.writeShort(output);
}
}
}
/**
* Read a four-byte integer value. Since unsigned values can exceed the capacity of an int,
* this value is stored as a long.
*
* @param signed if true, value will be signed
* @param isBigEndian if true, value will be read as a big-endian value; false for small-endian
* @return the two-byte value as a long
* @throws IOException if read error occurs
*/
public long read4ByteInt(boolean signed, boolean isBigEndian) throws IOException {
if (signed) {
if (isBigEndian) {
return (long)this.readInt();
} else {
int input = this.readInt();
input = Integer.reverseBytes(input);
return (long)input;
}
} else {
if (isBigEndian) {
int val = this.readInt();
long output = val & 0xffffffffL;
return output;
} else {
int val = this.readInt();
val = Integer.reverseBytes(val);
long output = val & 0xffffffffL;
return output;
}
}
}
/**
* Write a 4-byte integer to a file.
*
* @param value the value expressed as a long
* @param signed whether the value should be written as a signed or unsigned value
* @param isBigEndian true if the value should be written as big-endian, false for small-endian
* @throws IOException if value is out of range, or a write error occurs
*/
public void write4ByteInt(long value, boolean signed, boolean isBigEndian) throws IOException {
if (signed) {
if ((value < -2147483648) || (value > 2147483647)) {
throw new IOException("Long value is out of range");
}
} else {
if ((value < 0) || (value > 4294967295L)) {
throw new IOException("Long value is out of range");
}
}
if (signed) {
if (isBigEndian) {
this.writeInt((int)value);
return;
} else {
int output = Integer.reverseBytes((int)value);
this.writeInt(output);
}
} else {
if (isBigEndian) {
int output = (int)(value & 0xffffffffL);
this.writeInt(output);
} else {
int output = (int)(value & 0xffffffffL);
output = Integer.reverseBytes(output);
this.writeInt(output);
}
}
}
}
Add new comment