4

我使用 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);
    }

现在我想从这样的文件中读取。我不想指定要读取的字节数。我希望能够使用对象输入流直接读取对象。如何做到这一点?

必须使用随机访问文件,因为我需要写入文件中的不同位置。我还在一个单独的数据结构中记录了写入对象的位置。

4

4 回答 4

3

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

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

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

于 2011-09-14T13:31:43.187 回答
2

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

于 2011-09-12T16:52:05.123 回答
1

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

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

读取对象时,首先读取长度。这将告诉您要读取多少字节才能获取您的对象。与您已经在写入方面所做的类似,您可以将数据读入 abyte[]然后使用ByteArrayInputputStreamand ObjectInputStream

于 2011-09-12T17:14:38.197 回答
1

您可以在's对象上使用FileInputStream构造,如下所示:RandomAccesFileFileDescriptor

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

假设 RandomAccessFile 被称为 raf。

于 2011-09-12T21:48:27.183 回答