在將一些處理後的內容寫出到輸出流之後,我需要重新訪問流的開始並寫出一些內容元數據。我正在寫的數據非常大,高達4Gb,並且可能直接寫入文件或寫入內存緩衝區,具體取決於各種環境因素。如何實現可以倒回的OutputStream?
如何實現一個OutputStream,它允許我在完成內容寫入後寫出標題?
在將一些處理後的內容寫出到輸出流之後,我需要重新訪問流的開始並寫出一些內容元數據。我正在寫的數據非常大,高達4Gb,並且可能直接寫入文件或寫入內存緩衝區,具體取決於各種環境因素。如何實現可以倒回的OutputStream?
如何實現一個OutputStream,它允許我在完成內容寫入後寫出標題?
這是一個隨機存取文件輸出流。
請注意,如果將其用於大量流式輸出,您可以暫時將其包裝在BufferedOutputStream中以避免大量小寫操作(只需非常確定在丟棄包裝器或直接使用基礎流之前刷新它)。
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
如果您知道標題的大小,可以先寫一個空白標題,然後回到最後用RandomAccessFile
來修復它。如果你不知道標題的大小,那麼你有一個基本的理由,即文件系統通常不允許你插入數據。所以你需要寫入一個臨時文件然後寫入真實文件。
我們知道頭的大小,但是我們無法找到具有允許在流中的任意點寫入的通用OuptutStream。 – 2009-05-05 16:32:22
你寫出來。關閉文件。打開一個RandomAccessFile。寫頭。關閉RandomAccessFile。 – 2009-05-05 16:43:32
Lucene似乎有一個實現;和api看起來不錯。
getFilePointer()
void seek(long pos)
http://lucene.apache.org/java/1_4_3/api/org/apache/lucene/store/OutputStream.html
我想他們緊裹RandomAccessFile
一種方式將是對初始內容第一寫入到存儲器緩衝區,然後報頭插入「真正的」輸出流,隨後的緩衝沖洗內容,並從其上寫入非緩衝流。這聽起來像初始部分不會那麼長,使緩衝合理。 至於實現它,你可以使用ByteArrayOutputStream進行緩衝,然後讓你的OutputStream類以「真實」輸出流作爲參數;並根據需要在兩者之間切換。您可能需要擴展OutputStream API以允許定義要寫入的元數據,因爲該觸發器會從緩衝模式切換。
正如其他答案所述,RandomAccessFile也可以工作,但不會實現OutputStream。
它沒有,遺憾的是,但這主要是因爲我不得不改變我的設計,由於其他考慮。 這仍然是一個很好的答案。 – 2009-08-13 15:43:03