스파스 파일의 내용을 보는 방법은 무엇입니까?

스파스 파일의 내용을 보는 방법은 무엇입니까?

ls -l을 사용하여 크기를 확인하면 "파일"의 크기가 15TB로 표시됩니다.

ls -l
total 16
-rw-r--r-- 1 root root 15393162788865 May 30 13:41 file

du 명령을 사용하여 "파일"의 크기를 확인하면 다음과 같이 표시됩니다.

du -a file 
12  file

인터넷 검색을 통해 해당 파일이 희소 파일일 수 있다는 결론에 도달했습니다. 읽어보니 less, tail, cat, hexdump 등과 같은 명령은 시간이 오래 걸립니다.

이것은 filefrag의 출력입니다.

filefrag -e file 
Filesystem type is: ef53
File size of file is 15393162788865 (3758096385 blocks of 4096 bytes)
 ext:       logical_offset:        physical_offset: length:   expected: flags:
   0:         0..        0:   22261760..  22261760:      1:            
   1: 3169274812..3169274812:   22268860..  22268860:      1: 3191536572:
   2: 3758096383..3758096383:   22271999..  22271999:      1:  611090431: last
file: 3 extents found

파일의 구멍/0을 보지 않고 Linux 터미널에서 파일의 내용만 볼 수 있는 방법이 있는지 궁금합니다.

답변1

최신 Linux 시스템에서는 해당 확장을 SEEK_DATA통해 애플리케이션이 희소 파일을 읽을 때 "구멍"을 건너뛸 수 있습니다.SEEK_HOLElseek(2)

이전 시스템에서는 ioctl(FIBMAP)가능하며 기본 장치에서 직접 데이터를 읽을 수 있습니다(그러나 기능 FIBMAP이 필요함 CAP_SYS_RAWIO).

불행히도 저는 이러한 유틸리티를 사용하는 coreutils/표준 유틸리티를 모릅니다.

sparse_cat다음은 이를 사용하여 매우 큰 희소 파일에서 데이터를 즉시 덤프하는 작은 데모입니다 .

예:

$ cc -Wall -O2 sparse_cat.c -s -o sparse_cat

$ echo 1st | dd conv=notrunc status=none bs=1 seek=10M of=/tmp/sparse
$ echo 2nd | dd conv=notrunc status=none bs=1 seek=10G of=/tmp/sparse
$ echo 3rd | dd conv=notrunc status=none bs=1 seek=10T of=/tmp/sparse
$ ls -l /tmp/sparse
-rw-r--r-- 1 ahq ahq 10995116277764 May 30 16:29 /tmp/sparse
$ ./sparse_cat </tmp/sparse >/dev/tty
          a00000           a01000
1st
       280000000        280001000
2nd
     a0000000000      a0000000004
3rd

참고: 단순화를 위해 모든 파일 열기 코드(항상 sparse_cat < input대신 사용해야 함)와 sparse_cat input이 플래그로 열린 tty 간의 잘못된 상호 작용에 대한 해결 방법(명시적으로 사용됨)을 생략했습니다.sendfile(2)O_APPEND>/dev/tty

또한 데이터/홀 범위에는 블록 단위가 있습니다. 1st위 예의 문자열 뒤에는 실제로 block size - 4nul 바이트가 옵니다.

sparsecat.c

#define _GNU_SOURCE
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/sendfile.h>

int main(void){
        off_t hole, data, pos, len; typedef unsigned long long ull;
        for(hole = 0;; data = hole){
                if((data = lseek(0, hole, SEEK_DATA)) == -1){
                        if(errno == ENXIO) return 0;
                        err(1, "lseek +data");
                }
                if((hole = lseek(0, data, SEEK_HOLE)) == -1)
                        err(1, "lseek +hole");
                dprintf(2, "%16llx %16llx\n", (ull)data, (ull)hole);
                for(pos = data; pos < hole;){
                        len = hole - pos; if(len > INT_MAX) len = INT_MAX;
                        if((len = sendfile(1, 0, &pos, len)) == 0) return 0;
                        if(len < 0) err(1, "sendfile");
                }
        }
}

관련 정보