5

Хорошо, у меня есть куча файлов vCard размером от 200 до 300 байт.

Пытаясь получить их в архиве, я удивился, почему это занимает так много времени, и обнаружил, что существует один файл с неправильным размером. И ls, и stat показывают размер около 8,1 терабайт. Это удивительно, потому что мой SSD имеет размер всего около 250 гигабайт.

Есть и другие файлы с неправильным размером, но это, безусловно, самый большой файл. Я уже дал fsck, но в файловой системе (ext4), похоже, нет ошибок. Как я могу избавиться от этого неправильного размера?

Спасибо Wolle

2 ответа2

1

vCard представляется в формате текстового файла. Это хорошо, так как текстовые файлы не должны содержать нули - это поможет, если операционная система ошибочно считает, что файл является разреженным файлом, содержащим очень длинные последовательности нулей.

Вы можете использовать ls -lks bigfile чтобы увидеть, отличается ли занимаемое пространство от видимого.

Вы можете использовать dd для извлечения фрагментов данных (например, только первые 500 байтов) в новый файл. Затем вы можете использовать hexdump чтобы увидеть, есть ли в этом чанке восстанавливаемый текст.

Если вы обнаружите, что файл заполнен длинными последовательностями нулей, вы можете попробовать использовать скрипт для чтения файла и записать только ненулевые данные в новый файл. Таким образом, вы можете при определенных усилиях создать действительный файл vCard обычного размера.

в качестве альтернативы используйте strings bigfile для извлечения текста из огромного файла

Многие из этих операций займут много времени в файле ig. Вы можете практиковаться на чем-то меньшем ...


Вот файл vCard

$ cat gump.vcard
BEGIN:VCARD
VERSION:2.1
N:Gump;Forrest
FN:Forrest Gump
...
EMAIL;PREF;INTERNET:forrestgump@example.com
REV:20080424T195243Z
END:VCARD

$ file gump.vcard
gump.vcard: vCard visiting card

давайте сделаем коррумпированную разреженную версию

$ dd of=sparse-file bs=1k seek=5120 count=0
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0 s, Infinity B/s

$ cat gump.vcard sparse-file > sparse-gump.vcard

$ cp --sparse=always sparse-gump.vcard really-sparse-gump.vcard

$ ls -lks *sparse*
   0 -rw-r--r-- 1 rgb rgb 5120 Jul 11 18:09 sparse-file
5136 -rw-r--r-- 1 rgb rgb 5121 Jul 11 18:10 sparse-gump.vcard
   4 -rw-r--r-- 1 rgb rgb 5121 Jul 11 18:18 really-sparse-gump.vcard

Обратите внимание, что размер на диске последнего файла составляет 4 блока, но он содержит 5121 блок данных.

Давайте посмотрим, что там

$ hexdump really-sparse-gump.vcard | head -n 3
0000000 4542 4947 3a4e 4356 5241 0a44 4556 5352
0000010 4f49 3a4e 2e32 0a31 3a4e 7547 706d 463b
0000020 726f 6572 7473 460a 3a4e 6f46 7272 7365

$ hexdump really-sparse-gump.vcard | tail
0000230 4120 656d 6972 6163 450a 414d 4c49 503b
0000240 4552 3b46 4e49 4554 4e52 5445 663a 726f
0000250 6572 7473 7567 706d 6540 6178 706d 656c
0000260 632e 6d6f 520a 5645 323a 3030 3038 3234
0000270 5434 3931 3235 3334 0a5a 4e45 3a44 4356
0000280 5241 0a44 0000 0000 0000 0000 0000 0000
0000290 0000 0000 0000 0000 0000 0000 0000 0000
*
0500280 0000 0000
0500284

Обратите внимание на * линию между смещениями 290 и 0500280 - вот где живут все воображаемые нули.

$ strings really-sparse-gump.vcard > new-gump.vcard

$ ls -lks new-gump.vcard
4 -rw-r--r-- 1 rgb rgb 1 Jul 11 18:30 new-gump.vcard

$ cat new-gump.vcard
BEGIN:VCARD
VERSION:2.1
N:Gump;Forrest
FN:Forrest Gump
...
EMAIL;PREF;INTERNET:forrestgump@example.com
REV:20080424T195243Z
END:VCARD

Мы восстановили нашу vCard нормального размера из огромного файла. Ваш пробег может меняться.

0

В Linux (начиная с версии 3.1) вы можете использовать lseek() с SEEK_DATA и / или SEEK_HOLE чтобы идентифицировать позиции данных и дыр в разреженном файле. Повторяя вызов с возрастающим смещением, вы можете читать байты, идентифицированные как данные, и записывать их в другой файл по мере необходимости. Возможно, что-то вроде этого (проверка ошибок и другие скуки опущены для простоты):

int fd0 = open(file, O_RDONLY, S_IRWXU);
int fd1 = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
off_t eof = lseek(fd0, 0, SEEK_END);
off_t cur = 0;
char buf[8192];
while (cur < eof) {
  off_t d = lseek(fd0, cur, SEEK_DATA);
  off_t h = lseek(fd0, d, SEEK_HOLE);
  lseek(fd0, d, SEEK_SET);
  size_t dlen = min(h - d, 8192);
  ssize_t rlen = read(fd0, buf, dlen);
  ssize_t r = write(fd1, buf, rlen);
  cur = d + rlen;
}
close(fd0);
close(fd1);

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .