Java Binary I/O

Binary data is often referred to as byte streams. This contrasts to readable text files covered elsewhere. Byte streams handle Java primitive types and the String objects only. FileWriter and FileReader are replaced with FileInputStream and FileOutputStream, and their buffered classes also apply.

public someFunc() throws IOException {

    try (DataOutputStream someFile = new DataOutputStream(
        new BufferedOutputStream(
            new FileOutputStream("someFileName.dat")))) 
            {

            for (...) {
                someFile.writeInt(somePOJO.getIntValue);
                someFile.writeUTF(somePOJO.getSomeString());
            }

    }
}

Under the hood, the methods shift bits as they send data along the byte stream to a file. Hence, the resultant file is largely unreadable in part.

One can read from a byte stream as folows:

try(DataInputStream someFile = 
    new DataInputStream(
        new BufferedInputStream(
            new FileInputStream("someFileName.dat")))) {

    boolean eof = false;
    while(!eof) {
        try {
            int someInt = someFile.readInt();
            String someString = someFile.readUTF();
            
            System.out.println("Int found " someInt);
            System.out.println("String found " + someString);            
        } catch(EOFException e) {
            // this ultimately forces the loop to terminate at
            eof = true;
        }
    }

    } catch(IOException io) {
    System.out.println("IO Exception: " + io.printStackTrace());
}

Java objects and serialisation

One can store the fields or properties of a Java object in a file. To do this, one must convert the object the object into a form which can be saved, a process known as serialisation. While doing so, a serial UUID is needed and is generated by default. It is generally recommended to override the UUID that is normally provided. One declares the interface Serializable, a function-less interface. All classes instantiated in a given class must also implement the Serializable interface. All Java primitives are serialisable.

public class SomeClass implements Serializable {
    // SomeClass properties; all classes instanced here must also implement Serializable
    private long serialVersionUID = 1L;

    // ...
}

The Java object can be stored to disk as follows:

try (ObjectOutputStream someFile = 
    new ObjectOutputStream(
      new BufferedOutputStream(
        new FileOutputStream("someFileName.dat")))) {

    for(...) {
      someFile.writeObject(objectInstance);
    }

}

Storing and retrieving objects as opposed to saving to binary or text files one property at a time is much simpler to code. It is possible to mix serialised objects and primitive types in the stream and resultant file.

The object can be read from a binary file as follows:

try(ObjectInputStream someFile = 
  new ObjectInputStream(
    new BufferedInputStream(
        new FileInputStream("someFileName.dat")))) {

  boolean eof = false;

  while(!eof) {
      try {
          POJO pojo = (POJO) someFile.readObject();
          System.out.println("Got object with int " + pojo.getInt());
          System.out.println("Got object with long " + pojo.getLong());
          ...
      } catch(EOFException e) {
        // terminate the loop here
          eof = true;
      }
  }

} catch(IOException io) {
  System.out.println("IO Exception" + io.getMessage());
} catch(ClassNotFoundException e) {
  System.out.println("ClassNotFoundException " + e.getMessage());
}

As a side-note, the RandomAccessFile is briefly mentioned here. This file can be considered a flat-file form of a database system, where data occupies given uniform locations in a file, just as an array is organised. Taken from the official docs:

Instances of this class support both reading and writing to a random access file. A random access file behaves like a large array of bytes stored in the file system. There is a kind of cursor, or index into the implied array, called the file pointer; input operations read bytes starting at the file pointer and advance the file pointer past the bytes read.

In many cases, if a RandomAccessFile is considered then it may prove more efficient to employ a database system, such SQL.