blue sky
blue sky

Reputation: 161

RandomAccessFile writing to file properly, but upon retrieval of records it fails

I am a computer science student studying the IB diploma. I have an assignment involving the RAF(RandomAccessFile) class and I have to use it in the following program. I understand that using an ArrayList and serializing the program to the file is better, but this is coming on my exam and as a result I have to learn this. It's my third attempt at understanding this concept and it's driving me crazy.

The goal with this program is for me to have a .dat file filled with records-- each of the same size, with different fields within it. The program, in the end, should be a GUI with the different fields displayed, and it should allow the user to add entries as well as search, sort, edit and delete entries.

The GUI I created, in NetBeans, looks as follows:

enter image description here

And as I need to create records based on the byte size of each field, I devised the following image, that contains the maximum size of each field in # of characters as well as an example image to verify my reasoning:enter image description here

Having realized that the byte size of each record is 102, I used this knowledge to further the program by creating a method to write records to the binaryFile. Then I created one that is meant to bring the records back onto the file. However, this is where things are going awry. If I enter just one record, it's almost okay. I can enter this single record...

enter image description here enter image description here

But if I close the program and then re-open it, the age of the horse changes:

enter image description here

and if I try to retrieve more than one entry at once, the program won't retrieve all of them:

enter image description here Granted, here I just used 'keyboard smashes' to fill in more records quickly, but as you can see it combines different records and puts them all into that single column of the table. That isn't meant to happen.

Finally, I'm getting this exception each time:

Apr 12, 2016 10:18:17 PM horsemanager.HorseManager <init>
SEVERE: null
java.io.EOFException
    at java.io.RandomAccessFile.readChar(RandomAccessFile.java:773)
    at horsemanager.BinaryFile.getString(BinaryFile.java:118)
    at horsemanager.BinaryFile.readNextRecord(BinaryFile.java:99)
    at horsemanager.HorseManager.<init>(HorseManager.java:38)
    at horsemanager.HorseManager$7.run(HorseManager.java:453)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

This exception occurs regardless of the amount of records that are in the file.

BinaryFile.getString():

    public static String getString(int maxLength) throws IOException{
//maxLength indicates the maximum length of the particular field(eg. the horses name is maximum 25 characters so the maxLength in that case would be 25)
            String concat = ""; //to pull the entire string from the file
            int length = raf.readShort(); //to get the length of the string
            for(int j = 0 ; j<length; j++){ //to make sure to get the whole word
                    concat += raf.readChar();
//gets the word character by character. also, this is the line that has the error
            }
            for(int i=length; i<maxLength; i++){ //to skip forward if there is any blank space following the String
                raf.readChar();
            }
            return concat; //returns the full string
        }

BinaryFile.readNextRecord():

public static Object[] readNextRecord(int recordNumber) throws IOException {
        ID++;
        raf.seek(recordNumber * RecordLength);
        Object[] horse = {ID,
                getString((int)ShowNameLength),
                getString((int)BarnNameLength), //this line is the one that garners the error
                getString((int)CoatColorLength),
                getShort()} ;
                return horse;
    }

I feel like my Exceptions are occurring from the way that the records are written to the file, but I'm unsure as any modifications I've made to the file have not changed anything.

If more information is needed, ask me! Otherwise, this is the full BinaryFile.java class: http://pastebin.com/FWzmL2Aa

and this is the full HorseManager.java class: http://pastebin.com/hsHVmQFT

Upvotes: 0

Views: 490

Answers (1)

uncaught_exception
uncaught_exception

Reputation: 1078

You are using this to write the age. This basically writes the age as a sequence of 16 bit characters to the file.

public static void writeShort(int maxLength, short a) throws IOException {
    int length;
    String A = a + ""; // changing short to String
    if (A.length() < maxLength) {
        length = A.length();
    } else {
        length = maxLength;
        A = A.substring(0, maxLength);
    }

    int toBlanc = maxLength - length;
    char pointer;

    // writing the age as a sequence of 16 bit characters.
    for (int j = 0; j < A.length(); j++) {
        pointer = A.charAt(j);
        raf.writeChar(pointer);
    }

    for (int j = 0; j < (maxLength - A.length()); j++) {
        raf.writeChar(' ');
    }
} 

You are using this to read the age. This is reading the age as a short.

public static short getShort() throws IOException{
    return raf.readShort();
}

https://docs.oracle.com/javase/7/docs/api/java/io/RandomAccessFile.html#readShort%28%29

Your example: age changing from 12 to 49

When you write age 12 you are writing 16 bits of char '1' followed by 16 bits of char '2'. When you are reading the age your readShort() will only read the first 16 bits and assume them to be the binary representation of a short. The binary for '1' is 0000 0000 0011 0001 readShort() interprets this as 49. Now the second set of 16 bits is interpreted as something else and all subsequent records are jumbled up.

Solution

Make your readShort and writeShort consistent.

Upvotes: 2

Related Questions