1

I have a binary file, created in a Java program. The binary file contains an array of User objects.

It was created like this:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Main {
    public static void main(String[] args) {

        User[] arrayOfUsers = new User[50];
        for (int i = 0; i < 50; i++){
            arrayOfUsers[i] = new User("Mr. ", i + "owitz");
        }

        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users.dat"));
            oos.writeObject(arrayOfUsers);
            oos.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

This is the User class:

import java.io.Serializable;

public class User implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;


    private String firstname;
    private String lastname;
    public User(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
    }
    public String getFirstname() {
        return firstname;
    }
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }



}

As of now, I only know how to read in the entire array at once. However, I typically only need to retrieve one or two User objects from the array and I know their positions.

Is there any way to read just the index I want to read, without reading in everything?

CodyBugstein
  • 21,984
  • 61
  • 207
  • 363

1 Answers1

3

You are not building a direct file, but just a sequential one that happens to contain a serializable version of a Java ArrayList. So you can only read back the whole ArrayList in memory to process it again and get access to an individual element.

If you want to be able to access directly to an element just knowing its index, you will have to build a real direct file or an indexed file. A direct file has records of constant size, say s, so the offset for record n is n * s. You can use it through the Java class RandomAccessFile. But you should not directly use readUTF or writeUTF for direct files because the length of a String in bytes depends on the number and the type of characters:

  • All characters in the range '\u0001' to '\u007F' are represented by a single byte
  • The null character '\u0000' and characters in the range '\u0080' to '\u07FF' are represented by a pair of bytes
  • char values in the range '\u0800' to '\uFFFF' are represented by three bytes

(ref: Javadoc for DataInput)

So you'd better explicitely convert them to byte[] with String.getBytes() at least it is now easier to control the size, and manually write the size then the bytes. Alternatively, you could write skip the conversion to bytes, write the size in Char and then write the individual chars.


If you almost never modify values or add values, you could use an indexed file. The basics is to first have an array containing the offsets of records. That allows records not to have same size. A possible design would be:

  1. number of entries in the offset array (int n)
  2. n int for the offsets
  3. data

To write the file, you compute the begin of the data region: (1 + n) * 4, an create an int array for storing the offsets. Then you write n+1 0 to the file to be correctly positionned, and write your string, consistently saving the position of write for first record. Finally you position back to 0, write the number of records and the offsets.

To read, just read the number of records, and the offsets. You can then navigate the file. This is mainly used for large records of unknown and variable sizes


And if you find that the above is too complex, just use databases. Derby or H2 can be used as embedded databases and that will be much simpler.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252