RandomAccessFile пишет в файл правильно, но при извлечении записей происходит сбой

Я студент компьютерных наук, получаю диплом IB. У меня есть задание, связанное с классом RAF(RandomAccessFile), и я должен использовать его в следующей программе. Я понимаю, что лучше использовать ArrayList и сериализовать программу в файл, но это предстоит на моем экзамене, и в результате я должен этому научиться. Это моя третья попытка понять эту концепцию, и это сводит меня с ума.

Целью этой программы является создание файла .dat, заполненного записями, каждая из которых имеет одинаковый размер, но содержит разные поля. Программа, в конце концов, должна представлять собой графический интерфейс с различными отображаемыми полями, и она должна позволять пользователю добавлять записи, а также искать, сортировать, редактировать и удалять записи.

Графический интерфейс, который я создал в NetBeans, выглядит следующим образом:

введите здесь описание изображения

И поскольку мне нужно создавать записи на основе размера байтов каждого поля, я разработал следующее изображение, которое содержит максимальный размер каждого поля в # символов, а также пример изображения для проверки моего рассуждение: введите здесь описание изображения

Поняв, что размер каждой записи равен 102 байтам, я использовал это знание для дальнейшего развития программы, создав метод для записи записей в бинарный файл. Затем я создал тот, который предназначен для возврата записей в файл. Однако именно здесь дела идут наперекосяк. Если я введу только одну запись, это почти нормально. Я могу ввести эту единственную запись...

введите здесь описание изображения введите здесь описание изображения

Но если я закрою программу, а потом снова открою, возраст лошади изменится:

введите здесь описание изображения

и если я попытаюсь получить более одной записи одновременно, программа не получит их все:

введите описание изображения здесь Конечно, здесь я просто использовал «разбивку клавиатуры», чтобы быстро заполнить больше записей, но, как вы можете видеть, он объединяет разные записи и помещает их все в один столбец таблицы. Этого не должно было случиться.

Наконец, я получаю это исключение каждый раз:

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)

Это исключение возникает независимо от количества записей в файле.

БинарныйФайл.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
        }

Двоичный файл.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;
    }

Я чувствую, что мои исключения возникают из-за того, что записи записываются в файл, но я не уверен, поскольку любые изменения, которые я внес в файл, ничего не изменили.

Если нужна дополнительная информация, спросите меня! В противном случае это полный класс BinaryFile.java: http://pastebin.com/FWzmL2Aa< /а>

и это полный класс HorseManager.java: http://pastebin.com/hsHVmQFT


person blue sky    schedule 12.04.2016    source источник


Ответы (1)


Вы используете это, чтобы написать возраст. Это в основном записывает возраст как последовательность 16-битных символов в файл.

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(' ');
    }
} 

Вы используете это, чтобы прочитать возраст. Это чтение возраста как короткое.

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

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

Ваш пример: изменение возраста с 12 до 49 лет

Когда вы пишете возраст 12 лет, вы пишете 16 битов символа «1», за которыми следуют 16 битов символа «2». Когда вы читаете возраст, ваш readShort() будет читать только первые 16 бит и считать их двоичным представлением короткого замыкания. Двоичный код для «1» — 0000 0000 0011 0001. readShort() интерпретирует это как 49. Теперь второй набор из 16 бит интерпретируется как что-то другое, и все последующие записи перемешиваются.

Решение

Сделайте ваши readShort и writeShort согласованными.

person uncaught_exception    schedule 12.04.2016
comment
я должен изменить его, чтобы читать как строку, а затем просто проанализировать ее? - person blue sky; 12.04.2016
comment
Это должно сработать. Просто сделайте это, как вы сделали другие поля. Если вы читаете как строку, вы также должны писать как строку. Просто используйте методы writeString() и readString(), которые вы использовали в других местах. - person uncaught_exception; 12.04.2016