2009-05-05 25 views
7

在將一些處理後的內容寫出到輸出流之後,我需要重新訪問流的開始並寫出一些內容元數據。我正在寫的數據非常大,高達4Gb,並且可能直接寫入文件或寫入內存緩衝區,具體取決於各種環境因素。如何實現可以倒回的OutputStream?

如何實現一個OutputStream,它允許我在完成內容寫入後寫出標題?

+0

它沒有,遺憾的是,但這主要是因爲我不得不改變我的設計,由於其他考慮。 這仍然是一個很好的答案。 – 2009-08-13 15:43:03

回答

10

這是一個隨機存取文件輸出流。

請注意,如果將其用於大量流式輸出,您可以暫時將其包裝在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 
2

如果您知道標題的大小,可以先寫一個空白標題,然後回到最後用RandomAccessFile來修復它。如果你不知道標題的大小,那麼你有一個基本的理由,即文件系統通常不允許你插入數據。所以你需要寫入一個臨時文件然後寫入真實文件。

+0

我們知道頭的大小,但是我們無法找到具有允許在流中的任意點寫入的通用OuptutStream。 – 2009-05-05 16:32:22

+0

你寫出來。關閉文件。打開一個RandomAccessFile。寫頭。關閉RandomAccessFile。 – 2009-05-05 16:43:32

0

一種方式將是對初始內容第一寫入到存儲器緩衝區,然後報頭插入「真正的」輸出流,隨後的緩衝沖洗內容,並從其上寫入非緩衝流。這聽起來像初始部分不會那麼長,使緩衝合理。 至於實現它,你可以使用ByteArrayOutputStream進行緩衝,然後讓你的OutputStream類以「真實」輸出流作爲參數;並根據需要在兩者之間切換。您可能需要擴展OutputStream API以允許定義要寫入的元數據,因爲該觸發器會從緩衝模式切換。

正如其他答案所述,RandomAccessFile也可以工作,但不會實現OutputStream。