java - create - outputstream android
¿Cómo puedo implementar un OutputStream que pueda rebobinar? (4)
Después de escribir el contenido procesado en una transmisión de salida, necesito volver a visitar el comienzo de la transmisión y escribir algunos metadatos de contenido. Los datos que estoy escribiendo son muy grandes, tanto como 4Gb, y pueden escribirse directamente en un archivo o en un búfer en memoria, dependiendo de varios factores ambientales.
¿Cómo puedo implementar un OutputStream que me permite escribir encabezados después de completar la escritura del contenido?
Aquí hay una secuencia de salida de archivo de acceso aleatorio.
Tenga en cuenta que si lo usa para una gran cantidad de salida transmitida, puede envolverlo temporalmente en un BufferedOutputStream para evitar muchas escrituras pequeñas (solo asegúrese de enjuagarlo antes de descartar el envoltorio o usar la transmisión subyacente directamente).
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
Lucene parece tener una implementación; y la API se ve bien
getFilePointer()
void seek(long pos)
http://lucene.apache.org/java/1_4_3/api/org/apache/lucene/store/OutputStream.html
Supongo que envuelven un RandomAccessFile
Si conoce el tamaño del encabezado, puede escribir un encabezado en blanco inicialmente y luego volver a arreglarlo con RandomAccessFile
al final. Si no conoce el tamaño del encabezado, entonces tiene una fundamental que los sistemas de archivos generalmente no le permiten insertar datos. Entonces necesita escribir en un archivo temporal y luego escribir el archivo real.
Una forma sería escribir primero los contenidos iniciales en un búfer de memoria, luego los encabezados en el flujo de salida ''real'', seguido por el lavado de los contenidos almacenados en el búfer, y desde allí simplemente escribir en el flujo no amortiguado. Parece que el segmento inicial no sería tan largo, para hacer que el almacenamiento en búfer sea razonable. En cuanto a su implementación, puede usar ByteArrayOutputStream para el almacenamiento en búfer, y luego hacer que su clase OutputStream tome la corriente de salida "real" como argumento; y solo cambia entre los dos según sea necesario. Es posible que necesite extender la API de OutputStream para permitir la definición de los metadatos a escribir, ya que eso activa el cambio del modo de almacenamiento en búfer.
Como se menciona en la otra respuesta, RandomAccessFile también funcionaría, aunque no implementaría OutputStream.