![Как просмотреть содержимое разреженного файла?](https://rvso.com/image/154474/%D0%9A%D0%B0%D0%BA%20%D0%BF%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%D0%B5%D1%82%D1%8C%20%D1%81%D0%BE%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D0%BC%D0%BE%D0%B5%20%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE%20%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%3F.png)
Размер «файла» показывает 15 ТБ, когда я проверяю размер с помощью ls -l
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
, а не sparse_cat input
) и все обходные пути для неправильного взаимодействия между sendfile(2)
и tty, открытыми с этим O_APPEND
флагом (используйте >/dev/tty
явно).
Также обратите внимание, что диапазоны данных/дырок имеют блочную гранулярность — 1st
за строкой из примера выше фактически следуют block size - 4
нулевые байты.
разреженный_кот.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");
}
}
}