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

发布于 2024-12-04 02:39:07 字数 657 浏览 1 评论 0原文

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

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

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

I wrote a file using Java's FileChannel class that uses RandomAccessFiles. I wrote objects at various locations in the file. The objects were of variable sizes but all of the same class. I wrote the objects using the following idea :

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

Now I want to read from such a file. I dont want to have to specify the number of bytes to read. I want to be able to read the object directly using Object Input Stream. How to achieve this ?

I have to use Random Access Files because I need to write to different positions in file. I am also recording in a separate data structure, the locations where objects have been written.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

云巢 2024-12-11 02:39:07

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

不,你不知道。您可以通过其通道重新定位 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 中。在这种特定情况下,文件流在每次使用之前都会重新定位,这可以提供性能优势。但是请注意,缓冲流可以读取比需要的更多的字节,并且在某些情况下使用按需构造对象流,这将是一个非常糟糕的主意。

I have to use Random Access Files because I need to write to different
positions in file.

No, you don't. You can reposition a FileOutputStream or FileInputStream via its channel.

That would significantly simplify your writing code as well: you wouldn't need to use the buffer or channel, and depending on your needs you could omit the ByteArrayOutputStream as well. However, as you note in a comment, you won't know the size of the object in advance, and the ByteArrayOutputStream is a useful way to verify that you don't overrun your allotted space.

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

To read the objects, do the following:

FileInputStream fis = // an initialized stream

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

One comment here: I wrapped the FileInputStream in a BufferedInputStream. In this specific case, where the file stream is repositioned before each use, that can provide a performance benefit. Be aware, however, that the buffered stream can read more bytes than are needed, and there are some situations using construct-as-needed object streams where it would be a really bad idea.

无法言说的痛 2024-12-11 02:39:07

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

Why doesn't seek work for you? I believe you need to seek() to correct locations and then just read objects using your object stream. Also, if you store the correct locations of serialized objects, why don't you store their sizes? In this case you may apply ObjectInputStream against bytes you read from file.

千柳 2024-12-11 02:39:07

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

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

读取对象时,首先读取长度。这将告诉您还需要读取多少字节才能获取对象。与您在写入方面已经执行的操作类似,您可以将数据读取到 byte[] 中,然后使用 ByteArrayInputputStreamObjectInputStream

The simplest solution that comes to mind is to write out the length of the array before writing out the array itself:

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

When reading the object, you first read the length. This'll tell you how many further bytes to read to get your object. Similarly to what you are already doing on the writing side, you could read the data into a byte[] and then use ByteArrayInputputStream and ObjectInputStream.

云巢 2024-12-11 02:39:07

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

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

假设 RandomAccessFile 名为 raf。

You could use a FileInputStream constructed on the RandomAccesFile's FileDescriptor object, like so:

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

Assuming that the RandomAccessFile is called raf.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文