![如何查看稀疏文件的內容?](https://rvso.com/image/154474/%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8B%E7%A8%80%E7%96%8F%E6%96%87%E4%BB%B6%E7%9A%84%E5%85%A7%E5%AE%B9%EF%BC%9F.png)
當我使用 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_HOLE
lseek(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 - 4
nul 位元組。
稀疏貓.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");
}
}
}