エンドレスストリームをファイルに保存するにはどうすればいいですか?

エンドレスストリームをファイルに保存するにはどうすればいいですか?
  • バイナリ データのストリーム ( /dev/random/dev/zeroなど) を用意してみましょう。
  • 最大サイズが N になるファイルを用意しましょう。
  • N はギガバイトの順です。

ありますかエレガントなLinuxでこれを実現するための方法/技術/ハックファイル連続的に書き込まれるデータは最大 N バイトの長さで、常に最後に書き込まれたデータのみ (順番に) 含まれますか? これは、大きな移動 (ファイルからファイル、メモリからファイル) がなく、最後/最初のデータ ブロックを少し調整するだけであることを意味します。

私が探しているトリックは、ファイルを先に進めて、古すぎるコンテンツ(これによりファイル サイズが N を超えて増加する)を事実上忘れること、つまりコンテンツのローテーションです。

望ましい原則は次のように表現できます。

inp = fopen(stream, "r");
out = fopen(file, "wN"); // "Special open" with maximal size of N

while (is_reading)
{        
    if (rd = fread(buff, block_size, 1, inp))
    {
        fwrite(buff, rd, 1, out); // Old content forgotten
        fflush(out);              // Allow others to instantly see the current content
    }
}

fclose(inp);
fclose(out);

答え1

Linuxでは、fallocate()ファイルの先頭のデータの割り当てを解除します。

ファイルスペースの割り当て解除

mode に FALLOC_FL_PUNCH_HOLE フラグ (Linux 2.6.38 以降で使用可能) を指定すると、offset から len バイト続くバイト範囲のスペースが解放されます (つまり、穴が作成されます)。指定された範囲内で、ファイルシステム ブロックの一部がゼロにされ、ファイルシステム ブロック全体がファイルから削除されます。呼び出しが成功すると、この範囲からの後続の読み取りではゼロが返されます。

...

lsまたは同様の方法で報告されるファイルサイズは変わりませんstatが、実際のディスク使用量は減ります。ファイルはスパースになりますファイルの「穴」からの読み取りを試行すると、それでも成功し、0読み取りプロセスに -filled バイトが返されます。

このようなもの:

size_t maxSize = 512UL * 1024UL * 1024UL;
char buffer[ 8 * 1024 ];
struct stat sb;
int in = open( inputFile, O_RDONLY );
int out = open( outputFile, O_WRONLY | O_CREAT | O_APPEND, 0644 );
fstat( out, &sb );
size_t fileSize = sb.st_size;

for ( ;; )
{
    ssize_t bytesRead = read( in, buffer, sizeof( buffer ) );
    if ( bytesRead < 0 )
    {
        break;
    }

    ssize_t bytesWritten = write( out, buffer, bytesRead );
    if ( bytesWritten < 0 )
    {
        break;
    }

    fileSize += bytesWritten;

    if ( fileSize > maxSize )
    {
        fsync( out );
        off_t endOfHole = fileSize - maxSize;
        fallocate( out, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
            0UL, endOfHole );
    }
}

これは、XFS、BTRFS、EXT4、および tmpfs でのみサポートされます。

また、より多くのエラー チェックが必要になり、そのままではコンパイルできない可能性もあります。また、最大サイズに達すると、fallocate()すべてのread()/write()サイクルが呼び出され、毎回ファイルの先頭から「穴」が開けられるため、非常に非効率的です。

この IO パターンでは、バッファリングされたfread()/を使用する意味もありません。十分な大きさのチャンクの/ を使用するだけです。fwrite()read()write()

関連情報