Linux

如何將無盡的流儲存到文件?

  • June 1, 2016
  • 讓我們有任何二進制數據流(如/dev/random/dev/zero等)。
  • 讓我們有一個最大可以為 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);

在 Linux 上,您可以使用fallocate()釋放文件開頭的數據。

釋放文件空間

在 mode 中指定 FALLOC_FL_PUNCH_HOLE 標誌(自 Linux 2.6.38 起可用)會在從 offset 開始並持續 len 個字節的字節範圍內釋放空間(即創建一個洞)。在指定範圍內,部分文件系統塊被清零,整個文件系統塊從文件中刪除。成功呼叫後,從此範圍內的後續讀取將返回零。

這不會改變lsorstat或類似報告的文件大小,但會減少實際磁碟使用量,因為文件將是 sparse。嘗試從文件中的“孔”讀取仍然會成功,並將0- 填充字節返回到讀取過程。

像這樣的東西:

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()足夠大的塊。

引用自:https://unix.stackexchange.com/questions/286919