Question

Après avoir écrit du contenu traité dans un flux de sortie, je dois revenir au début du flux et écrire des métadonnées de contenu. Les données que j’écris sont très volumineuses, jusqu’à 4 Go, et peuvent être écrites directement dans un fichier ou dans une mémoire tampon en mémoire, en fonction de divers facteurs environnementaux.

Comment puis-je implémenter un OutputStream qui me permet d'écrire des en-têtes après avoir terminé l'écriture du contenu?

Était-ce utile?

La solution

Voici un flux de sortie de fichier à accès aléatoire.

Notez que si vous l'utilisez pour une grande quantité de sorties en continu, vous pouvez l'envelopper temporairement dans BufferedOutputStream afin d'éviter de nombreuses écritures (veillez simplement à le vider avant de supprimer le wrapper ou d'utiliser directement le flux sous-jacent). / 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

Autres conseils

Si vous connaissez la taille de l'en-tête, vous pouvez écrire un en-tête vide, puis revenir en arrière pour le corriger avec RandomAccessFile à la fin. Si vous ne connaissez pas la taille de l'en-tête, il est fondamental que les systèmes de fichiers ne vous permettent généralement pas d'insérer des données. Vous devez donc écrire dans un fichier temporaire, puis écrire le fichier réel.

Lucene semble avoir une implémentation; et l’API va bien.

getFilePointer()
void seek(long pos)  

http: //lucene.apache .org / java / 1_4_3 / api / org / apache / lucene / store / OutputStream.html

Je suppose qu'ils enveloppent un RandomAccessFile <> / a>

Une solution consiste à écrire d’abord le contenu initial dans un tampon de mémoire, puis les en-têtes dans le flux de sortie "réel", suivi du vidage du contenu mis en mémoire tampon, puis d’écrire dans le flux non mis en mémoire tampon. Il semble que le segment initial ne serait pas si long pour rendre la mise en mémoire tampon raisonnable. En ce qui concerne son implémentation, vous pouvez utiliser ByteArrayOutputStream pour la mise en mémoire tampon, puis demander à votre classe OutputStream de prendre la valeur "real". flux de sortie comme argument; et juste basculer entre les deux si nécessaire. Vous devrez peut-être étendre l'API OutputStream pour permettre de définir ce que sont les métadonnées à écrire, car cela déclenche le passage du mode mis en tampon.

Comme mentionné dans l’autre réponse, RandomAccessFile fonctionnerait également, mais n’implémenterait pas OutputStream.

scroll top