我使用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直接读取对象。怎么做到这一点?
我有使用随机存取文件,因为我需要写入文件中的不同位置。我也在一个单独的数据结构中记录,即写入对象的位置。
答案 0 :(得分:3)
我必须使用随机访问文件,因为我需要写入不同的文件 在档案中的位置。
不,你没有。您可以通过其频道重新定位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
中。在这种特定情况下,在每次使用之前重新定位文件流,这可以提供性能优势。但请注意,缓冲流可以读取比所需更多的字节,并且在某些情况下使用构造所需的对象流,这将是一个非常糟糕的主意。
答案 1 :(得分:2)
为什么seek不适合你?我相信您需要seek()
来更正位置,然后使用对象流读取对象。此外,如果您存储序列化对象的正确位置,为什么不存储它们的大小?在这种情况下,您可以对从文件中读取的字节应用ObjectInputStream
。
答案 2 :(得分:1)
最简单的解决方案是在写出数组本身之前写出数组的长度:
while(rbb.hasRemaining()) {
fileChannel.writeLong(recordBytes.length);
fileChannel.write(rbb);
}
阅读对象时,首先阅读长度。这将告诉你要读取多少更多字节来获取对象。与您在写作方面已经完成的工作类似,您可以将数据读入byte[]
,然后使用ByteArrayInputputStream
和ObjectInputStream
。
答案 3 :(得分:1)
您可以使用在FileInputStream
的{{1}}对象上构建的RandomAccesFile
,如下所示:
FileDescriptor
假设RandomAccessFile被称为raf。