Чтение объектов из файла произвольного доступа - PullRequest
4 голосов
/ 12 сентября 2011

Я написал файл, используя класс FileChannel Java, который использует RandomAccessFiles. Я написал объекты в разных местах в файле. Объекты были переменного размера, но все одного класса. Я написал объекты, используя следующую идею:

ByteArrayOutputStream bos= new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos); out.writeObject(r); byte[] recordBytes= bos.toByteArray();

    ByteBuffer rbb= ByteBuffer.wrap(recordBytes);

    while(rbb.hasRemaining()) {
        fileChannel.write(rbb);
    }

Теперь я хочу прочитать из такого файла. Я не хочу указывать количество байтов для чтения. Я хочу иметь возможность читать объект напрямую, используя Object Input Stream. Как этого добиться?

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

Ответы [ 4 ]

3 голосов
/ 14 сентября 2011

Я должен использовать файлы произвольного доступа, потому что мне нужно записывать позиции в файле.

Нет, нет. Вы можете изменить положение FileOutputStream или FileInputStream через его канал.

Это также значительно упростит ваш код написания: вам не нужно будет использовать буфер или канал, и в зависимости от ваших потребностей вы также можете опустить ByteArrayOutputStream. Однако, как вы заметили в комментарии, вы заранее не будете знать размер объекта, и ByteArrayOutputStream - это полезный способ убедиться, что вы не переполните выделенное пространство.

Object obj = // something

FileOutputStream fos = // an initialized stream

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();

if (bos.size() > MAX_ALLOWED_SIZE)
   throw // or log, or whatever you want to do
else
{
    fos.getChannel().position(writeLocation);
    bos.writeTo(fos);
}

Чтобы прочитать объекты, сделайте следующее:

FileInputStream fis = // an initialized stream

fis.getChannel().position(offsetOfSerializedObject);
ObjectInputStream iis = new ObjectInputStream(new BufferedInputStream(fis));
Object obj = iis.readObject();

Один комментарий здесь: я завернул FileInputStream в BufferedInputStream. В этом конкретном случае, когда файловый поток перемещается перед каждым использованием, это может обеспечить выигрыш в производительности. Имейте в виду, однако, что буферизованный поток может читать больше байтов, чем необходимо, и в некоторых ситуациях используются потоки объектов конструкции по мере необходимости, где это будет действительно плохой идеей.

2 голосов
/ 12 сентября 2011

Почему seek не работает для вас?Я считаю, что вам нужно seek(), чтобы исправить местоположения, а затем просто читать объекты, используя ваш поток объектов.Кроме того, если вы храните правильные местоположения сериализованных объектов, почему бы вам не сохранить их размеры?В этом случае вы можете применить ObjectInputStream к байтам, которые вы прочитали из файла.

1 голос
/ 13 сентября 2011

Вы можете использовать FileInputStream, построенный на FileDescriptor объекте RandomAccesFile, например:

FileDescriptor f = raf.getFD();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));

Предполагая, что RandomAccessFile называется raf.

1 голос
/ 12 сентября 2011

Самое простое решение, которое приходит на ум, - записать длину массива перед записью самого массива:

while(rbb.hasRemaining()) {
        fileChannel.writeLong(recordBytes.length);
        fileChannel.write(rbb);
    }

При чтении объекта вы сначала читаете длину. Это скажет вам, сколько еще байтов нужно прочитать, чтобы получить ваш объект. Аналогично тому, что вы уже делаете на стороне записи, вы можете прочитать данные в byte[] и затем использовать ByteArrayInputputStream и ObjectInputStream.

...