从随机访问文件中读取对象

时间:2011-09-12 16:29:58

标签: java objectoutputstream filechannel

我使用Java的FileChannel类编写了一个使用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);
    }

ByteBuffer rbb= ByteBuffer.wrap(recordBytes); while(rbb.hasRemaining()) { fileChannel.write(rbb); }

现在我想从这样的文件中读取。我不想指定要读取的字节数。我希望能够使用Object Input Stream直接读取对象。怎么做到这一点?

使用随机存取文件,因为我需要写入文件中的不同位置。我也在一个单独的数据结构中记录,即写入对象的位置。

4 个答案:

答案 0 :(得分:3)

  

我必须使用随机访问文件,因为我需要写入不同的文件   在档案中的位置。

不,你没有。您可以通过其频道重新定位FileOutputStreamFileInputStream

这样可以大大简化您的编写代码:您不需要使用缓冲区或通道,根据您的需要,您也可以省略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中。在这种特定情况下,在每次使用之前重新定位文件流,这可以提供性能优势。但请注意,缓冲流可以读取比所需更多的字节,并且在某些情况下使用构造所需的对象流,这将是一个非常糟糕的主意。

答案 1 :(得分:2)

为什么seek不适合你?我相信您需要seek()来更正位置,然后使用对象流读取对象。此外,如果您存储序列化对象的正确位置,为什么不存储它们的大小?在这种情况下,您可以对从文件中读取的字节应用ObjectInputStream

答案 2 :(得分:1)

最简单的解决方案是在写出数组本身之前写出数组的长度:

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

阅读对象时,首先阅读长度。这将告诉你要读取多少更多字节来获取对象。与您在写作方面已经完成的工作类似,您可以将数据读入byte[],然后使用ByteArrayInputputStreamObjectInputStream

答案 3 :(得分:1)

您可以使用在FileInputStream的{​​{1}}对象上构建的RandomAccesFile,如下所示:

FileDescriptor

假设RandomAccessFile被称为raf。