- 讓我們擁有任何二進位資料流(如
/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()
取消分配文件開頭的資料。
釋放檔案空間
在模式下指定 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()
夠大的塊。