끝없는 스트림을 파일에 저장하는 방법은 무엇입니까?

끝없는 스트림을 파일에 저장하는 방법은 무엇입니까?
  • 이진 데이터 스트림(예 /dev/random: /dev/zero, 등)을 만들어 보겠습니다.
  • 최대 N 크기의 파일을 만들어 보겠습니다.
  • N이 기가바이트 단위라고 가정해 보겠습니다.

거기에 있습니까?어떤 우아한리눅스에서 사용하는 방법/기술/해킹, 이를 달성하기 위해파일연속적으로 기록되는 길이는 최대 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 바이트 동안 계속되는 바이트 범위의 공간 할당이 해제됩니다(즉, 구멍이 생성됩니다). 지정된 범위 내에서 부분 파일 시스템 블록이 0으로 설정되고 전체 파일 시스템 블록이 파일에서 제거됩니다. 호출이 성공한 후 이 범위에서 후속 읽기를 수행하면 0이 반환됩니다.

...

보고된 파일 크기는 변경되지 않지만 실제 디스크 사용량은 다음 lsstat같이 줄어듭니다.파일이 부족할 것입니다. 파일의 "구멍"에서 읽으려는 시도는 여전히 성공하며 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()충분히 큰 덩어리입니다.

관련 정보