- バイナリ データのストリーム (
/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()