在将一些已处理的内容写入输出流之后,我需要重新访问流的开头并写出一些内容元数据。我写的数据非常大,高达4Gb,可以直接写入文件或内存缓冲区,具体取决于各种环境因素。
如何实现一个OutputStream,允许我在完成内容编写后写出标题?
答案 0 :(得分:10)
这是一个随机访问文件输出流。
请注意,如果将其用于大量流式输出,您可以暂时将其包装在BufferedOutputStream中以避免大量小写(在丢弃包装器或直接使用底层流之前,请务必清除它)。 / p>
import java.io.*;
/**
* A positionable file output stream.
* <p>
* Threading Design : [x] Single Threaded [ ] Threadsafe [ ] Immutable [ ] Isolated
*/
public class RandomFileOutputStream
extends OutputStream
{
// *****************************************************************************
// INSTANCE PROPERTIES
// *****************************************************************************
protected RandomAccessFile randomFile; // the random file to write to
protected boolean sync; // whether to synchronize every write
// *****************************************************************************
// INSTANCE CONSTRUCTION/INITIALIZATON/FINALIZATION, OPEN/CLOSE
// *****************************************************************************
public RandomFileOutputStream(String fnm) throws IOException {
this(fnm,false);
}
public RandomFileOutputStream(String fnm, boolean syn) throws IOException {
this(new File(fnm),syn);
}
public RandomFileOutputStream(File fil) throws IOException {
this(fil,false);
}
public RandomFileOutputStream(File fil, boolean syn) throws IOException {
super();
File par; // parent file
fil=fil.getAbsoluteFile();
if((par=fil.getParentFile())!=null) { IoUtil.createDir(par); }
randomFile=new RandomAccessFile(fil,"rw");
sync=syn;
}
// *****************************************************************************
// INSTANCE METHODS - OUTPUT STREAM IMPLEMENTATION
// *****************************************************************************
public void write(int val) throws IOException {
randomFile.write(val);
if(sync) { randomFile.getFD().sync(); }
}
public void write(byte[] val) throws IOException {
randomFile.write(val);
if(sync) { randomFile.getFD().sync(); }
}
public void write(byte[] val, int off, int len) throws IOException {
randomFile.write(val,off,len);
if(sync) { randomFile.getFD().sync(); }
}
public void flush() throws IOException {
if(sync) { randomFile.getFD().sync(); }
}
public void close() throws IOException {
randomFile.close();
}
// *****************************************************************************
// INSTANCE METHODS - RANDOM ACCESS EXTENSIONS
// *****************************************************************************
public long getFilePointer() throws IOException {
return randomFile.getFilePointer();
}
public void setFilePointer(long pos) throws IOException {
randomFile.seek(pos);
}
public long getFileSize() throws IOException {
return randomFile.length();
}
public void setFileSize(long len) throws IOException {
randomFile.setLength(len);
}
public FileDescriptor getFD() throws IOException {
return randomFile.getFD();
}
} // END PUBLIC CLASS
答案 1 :(得分:2)
如果您知道标题的大小,可以先写一个空白标题,然后返回到最后用RandomAccessFile
进行修复。如果你不知道标题的大小,那么你有一个基本的文件系统通常不允许你插入数据。因此,您需要写入临时文件,然后编写真实文件。
答案 2 :(得分:1)
Lucene似乎有一个实现;而api看起来还不错。
getFilePointer()
void seek(long pos)
http://lucene.apache.org/java/1_4_3/api/org/apache/lucene/store/OutputStream.html
我猜他们会包裹RandomAccessFile
答案 3 :(得分:0)
一种方法是首先将初始内容写入内存缓冲区,然后将标头写入“实际”输出流,然后刷新缓冲内容,并从其上只写入非缓冲流。这听起来像初始段不会那么长,使缓冲合理。 至于实现它,您可以使用ByteArrayOutputStream进行缓冲,然后让您的OutputStream类将“实际”输出流作为参数;并根据需要在两者之间切换。您可能需要扩展OutputStream API以允许定义要写入的元数据,因为它会触发从缓冲模式切换。
正如另一个答案所提到的,RandomAccessFile也会起作用,虽然不会实现OutputStream。