Запись/чтение из файла randomacces

У меня есть проект, в котором я должен записывать данные (строки и целые числа) в двоичный файл с произвольным доступом и читать данные в отдельном классе. У меня проблема в том, что я пытаюсь перебрать файл и прочитать данные в определенном порядке (int, String, String, int), однако строки имеют разные размеры байтов.

Я получаю EOFException, но не могу понять почему.

Вот класс, который записывает данные. Часть требований состоит в том, чтобы ограничить количество байтов для строк и поймать определяемое пользователем исключение, если они превышены.

import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.ArrayList;
import java.io.File;

public class QuestionBank {
   private RandomAccessFile file;
   private ArrayList <Questions> listQuestions;

   public QuestionBank(){
      file = null;
      listQuestions = new ArrayList<Questions>();      
   }

   public void storeQuestion (Questions ques) throws IOException {

      ques = new Questions(ques.getQuesIDNum(), ques.getQuestion(), ques.getAnswer(), ques.getValue());

      listQuestions.add(ques);

      byte[] quesBytes = ques.getQuestion().getBytes("UTF-8");
      byte[] ansBytes = ques.getAnswer().getBytes("UTF-8");

      try {
           file = new RandomAccessFile(new File("Question.bin"), "rw");

           long fileSize = file.length();

           file.seek(fileSize);

           file.writeInt(ques.getQuesIDNum());

           file.writeUTF(ques.getQuestion());

           for (int i = 0; i <= 50 - ques.getQuestion().length(); i++){
              file.writeByte(50);
              }              
           if (quesBytes.length > 50) {
              throw new ByteSizeException("Question has too many bytes");
              }

           file.writeUTF(ques.getAnswer());

           for (int i = 0; i <= 20 - ques.getAnswer().length(); i++){
              file.writeByte(20);
              }
           if (ansBytes.length > 20) {
              throw new ByteSizeException("Answer has too many bytes");
              }

           file.writeInt(ques.getValue()); 

           file.close();
          } catch (IOException e) {

            System.out.println("I/O Exception Found");


          } catch (ByteSizeException eb) {

            System.out.println("String has too many bytes");
          }                
    }

Вот класс, который читает файл.

import java.util.ArrayList;
import java.util.Random;
import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.FileNotFoundException;

import java.io.File;

public class TriviaGame {
   public static final int RECORD = 78;
   private ArrayList<Questions> quesList;
   private int IDNum;
   private String question;
   private String answer;
   private int points;

   public TriviaGame() {
      quesList = new ArrayList<Questions>();
      IDNum = 0;
      question = "";
      answer = "";
      points = 0;
   }

   public void read(){ 
      try {
          RandomAccessFile file;

          file = new RandomAccessFile(new File("Question.bin"), "r");
          long fileSize = file.length();        
          long numRecords = fileSize/RECORD;

          file.seek(0);

          for (int i = 0; i < numRecords; i++){
             IDNum = file.readInt();
             question = file.readUTF();                                       
             answer = file.readUTF();                                              
             points = file.readInt();

             System.out.println("ID: " + IDNum + " Question: " + question + " Answer: " + answer + " Points: " + points);
         }
     file.close();

     } catch (IOException e) {
       System.out.println(e.getClass());
       System.out.println("I/O Exception found");   
    }  
  } 
}

Спасибо


person Jengland    schedule 25.10.2017    source источник
comment
Вы УВЕРЕНЫ, что ни одна запись данных не превышает RECORD длины?   -  person markspace    schedule 25.10.2017
comment
Опубликовать всю трассировку стека будет лучше.   -  person Alex    schedule 25.10.2017
comment
Это выглядит сломанным: file.writeByte(50); Вы уверены, что не хотели вместо этого написать 0?   -  person markspace    schedule 25.10.2017
comment
Ах, длина записи неверна. writeUTF() записывает два байта для длины, прежде чем начнет записывать символы. Максимальная длина вашего вопроса на самом деле составляет 52 байта, а не 50, как вы предполагали. То же самое для поля ответа. Документировано в методе readUTF().   -  person markspace    schedule 25.10.2017
comment
mark, спасибо, я понятия не имел, что метод writeUTF раньше записывает 2 байта. Поэтому, если я изменю ограничение оператора for на ‹= 52 и 22, я все равно получу то же исключение eof. Я прочитал ниже, где я должен пропускать пустые байты при чтении, возможно, это поможет   -  person Jengland    schedule 25.10.2017


Ответы (1)


file.writeUTF(ques.getQuestion());

Вот вы написали вопрос.

for (int i = 0; i <= 50 - ques.getQuestion().length(); i++){
    file.writeByte(50);
}              
if (quesBytes.length > 50) {
    throw new ByteSizeException("Question has too many bytes");
}

Здесь по какой-то неизвестной причине вы дополняете вопрос до 50 байт. Удалять. То же и с ответом. Вы используете readUTF() для чтения обоих, поэтому все, что вам нужно, это writeUTF() для их записи. Прокладка не требуется.

Или, если вы настаиваете на этом отступе, вы должны пропустить его при чтении: после первого readUTF() вам нужно пропустить этот отступ.

person user207421    schedule 25.10.2017
comment
Спасибо, я поместил туда заполнение, чтобы помочь в итерации в методе read(). Я искал другие способы анализа данных из файла, но этот казался логичным. Код неполный, но я намерен изменить метод, чтобы прочитать 5 случайных вопросов из файла. Моя логика заключается в том, что если я дополняю строки байтами, то каждая строка составляет 50 байтов. Строка плюс пустые байты. Но вы правы, мне нужно пропустить оставшиеся байты. - person Jengland; 25.10.2017