Как сохранить бесконечный поток в файл?

Как сохранить бесконечный поток в файл?
  • Давайте возьмем любой поток двоичных данных (типа /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) в режиме освобождает пространство (т. е. создает дыру) в диапазоне байтов, начиная со смещения и продолжаясь len байтов. В пределах указанного диапазона частичные блоки файловой системы обнуляются, а целые блоки файловой системы удаляются из файла. После успешного вызова последующие чтения из этого диапазона будут возвращать нули.

...

Это не изменит размер файла, сообщаемый lsили statили подобными, но это уменьшит фактическое использование диска, так какфайл будет разреженным. Попытка чтения из «дыр» в файле все равно будет успешной и вернет 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()и каждый раз будет пробивать «дыру» с самого начала файла.

Также нет смысла использовать буферизованный fread()/ fwrite()для этого шаблона ввода-вывода. Только read()/ write()достаточно большие куски.

Связанный контент