如何查看稀疏文件的内容?

如何查看稀疏文件的内容?

当我使用 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

我想知道是否有一种方法可以从 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,而不是)以及使用该标志打开的 ttyssparse_cat input之间的不良交互的任何解决方法(显式使用)。sendfile(2)O_APPEND>/dev/tty

另请注意,数据/空洞范围具有块粒度——1st上例中的字符串实际上后面跟着block size - 4nul 字节。

稀疏猫.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");
                }
        }
}

相关内容