2009-05-05 14 views
7

Dopo aver scritto del contenuto elaborato su un flusso di output, ho bisogno di rivisitare l'inizio dello stream e scrivere alcuni metadati del contenuto. I dati che sto scrivendo sono molto grandi, fino a 4 GB, e possono essere scritti direttamente in un file o in un buffer in memoria, a seconda dei vari fattori ambientali.Come posso implementare un OutputStream che posso riavvolgere?

Come posso implementare un OutputStream che mi consente di scrivere le intestazioni dopo aver completato la scrittura del contenuto?

+0

Non è stato, purtroppo, ma questo è in gran parte perché ho dovuto cambiare il mio disegno a causa di altre considerazioni. È ancora una buona risposta. –

risposta

10

Ecco un flusso di output del file di accesso casuale.

Si noti che se si utilizza per una grande quantità di output in streaming si può avvolgere temporaneamente in un BufferedOutputStream per evitare un sacco di piccole scrive (tanto per essere molto sicuri di sciacquare prima di eliminare l'involucro o con il flusso sottostante direttamente).

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

Se si conosce la dimensione dell'intestazione, è possibile scrivere inizialmente un'intestazione vuota, quindi tornare indietro per risolverlo con RandomAccessFile alla fine. Se non si conosce la dimensione dell'intestazione, è fondamentale che i file system in genere non consentano l'inserimento di dati. Quindi è necessario scrivere su un file temporaneo e quindi scrivere il file reale.

+0

Sappiamo la dimensione dell'intestazione, ma non è possibile trovare un OuptutStream generico che consenta la scrittura in un punto arbitrario nel flusso. –

+0

Lo scrivi. Chiudi il file Aprire un file RandomAccess. Scrivi l'intestazione. Chiudere il RandomAccessFile. –

+1

(Si noti che RandomAccessFile per prestazioni operative fa schifo, quindi utilizzare le operazioni con blocchi di grandi dimensioni.) –

0

Uno sarebbe di scrivere contenuto iniziale di un buffer di memoria, quindi intestazioni in streaming 'vera' uscita, seguita da lavaggio dei tamponata contenuto e da lì basta scrivere sul flusso non bufferizzato. Sembra che il segmento iniziale non sarebbe lungo, per rendere ragionevole il buffering. Per quanto riguarda l'implementazione, è possibile utilizzare ByteArrayOutputStream per il buffering e quindi fare in modo che la classe OutputStream consideri il flusso di output "reale" come argomento; e basta passare tra i due se necessario. Potrebbe essere necessario estendere l'API OutputStream per consentire la definizione di cosa sono i metadati da scrivere, poiché i trigger si commutano dalla modalità bufferizzata.

Come menzionato dall'altra risposta, RandomAccessFile potrebbe funzionare anche se non implementasse OutputStream.

+1

"I dati che sto scrivendo sono molto grandi, fino a 4 GB" – DJClayworth

Problemi correlati