8

処理されたコンテンツを出力ストリームに書き出した後、ストリームの先頭に戻ってコンテンツ メタデータを書き出す必要があります。私が書き込んでいるデータは非常に大きく、最大 4Gb であり、さまざまな環境要因に応じて、ファイルまたはメモリ内バッファーに直接書き込まれます。

コンテンツの書き込みが完了した後にヘッダーを書き出せるようにする OutputStream を実装するにはどうすればよいですか?

4

4 に答える 4

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
于 2009-05-05T17:15:40.823 に答える
2

ヘッダーのサイズがわかっている場合は、最初に空白のヘッダーを書き込んでから、戻ってRandomAccessFile最後に修正することができます。ヘッダーのサイズがわからない場合は、ファイルシステムでは通常データの挿入が許可されていないという基本事項があります。したがって、一時ファイルに書き込んでから、実際のファイルに書き込む必要があります。

于 2009-05-05T16:29:41.400 に答える
1

Luceneには実装があるようです。そしてAPIは大丈夫に見えます。

getFilePointer()
void seek(long pos)  

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

RandomAccessFileをラップしていると思います

于 2009-05-05T16:31:54.423 に答える
0

1つの方法は、最初に初期コンテンツをメモリバッファに書き込み、次にヘッダーを「実際の」出力ストリームに書き込み、次にバッファリングされたコンテンツをフラッシュし、そこからバッファリングされていないストリームに書き込むことです。バッファリングを合理的にするために、最初のセグメントはそれほど長くはないようです。実装に関しては、ByteArrayOutputStreamを使用してバッファリングし、OutputStreamクラスに「実際の」出力ストリームを引数として使用させることができます。必要に応じて2つを切り替えてください。OutputStream APIを拡張して、書き込むメタデータを定義できるようにする必要がある場合があります。これにより、バッファーモードからの切り替えがトリガーされます。

他の回答で述べたように、OutputStreamを実装していなくても、RandomAccessFileも機能します。

于 2009-05-05T16:32:21.177 に答える