Знаете ли вы, что tar до сих пор пишет архивы под магнитную ленту?
На магнитной ленте между записями оставались промежутки, которые занимали место. Поэтому tar объединял блоки в крупные записи. След этого решения виден даже в пустом архиве:
import tarfile, os
with tarfile.open("empty.tar", "w") as tar:
pass
print(os.path.getsize("empty.tar")) # 10240
print(open("empty.tar", "rb").read() == b"\x00" * 10240) # True
В архиве нет ни одного файла, но на диске он занимает десять килобайт – все они заполнены нулями.
Эти размеры зашиты в стандартную библиотеку Питона константами:
print(tarfile.BLOCKSIZE) # 512
print(tarfile.RECORDSIZE) # 10240
BLOCKSIZE – это блок формата, минимальная единица, которой оперирует tar. RECORDSIZE – размер ленточной записи, в нее входит двадцать блоков. Число двадцать называется blocking factor, и в утилите командной строки оно меняется флагом -b.
Нули появляются и там, где данные есть:
with open("a.txt", "w") as f:
f.write("hi")
with tarfile.open("one.tar", "w") as tar:
tar.add("a.txt")
print(os.path.getsize("one.tar")) # 10240
Два байта текста дают архив того же размера. Заголовок файла занимает один блок, содержимое – второй, дальше идет маркер конца архива из двух нулевых блоков, а остаток записи добивается нулями до 10240.
Смысл этой механики описан в мануале GNU tar: записи на ленте разделялись промежутками, которые тратили место впустую, и чем крупнее запись, тем экономнее расходуется лента.
Двадцать блоков – это компромисс, выбранный под железо семидесятых.
Код на салфетке x Кусочки кода
На магнитной ленте между записями оставались промежутки, которые занимали место. Поэтому tar объединял блоки в крупные записи. След этого решения виден даже в пустом архиве:
import tarfile, os
with tarfile.open("empty.tar", "w") as tar:
pass
print(os.path.getsize("empty.tar")) # 10240
print(open("empty.tar", "rb").read() == b"\x00" * 10240) # True
В архиве нет ни одного файла, но на диске он занимает десять килобайт – все они заполнены нулями.
Эти размеры зашиты в стандартную библиотеку Питона константами:
print(tarfile.BLOCKSIZE) # 512
print(tarfile.RECORDSIZE) # 10240
BLOCKSIZE – это блок формата, минимальная единица, которой оперирует tar. RECORDSIZE – размер ленточной записи, в нее входит двадцать блоков. Число двадцать называется blocking factor, и в утилите командной строки оно меняется флагом -b.
Нули появляются и там, где данные есть:
with open("a.txt", "w") as f:
f.write("hi")
with tarfile.open("one.tar", "w") as tar:
tar.add("a.txt")
print(os.path.getsize("one.tar")) # 10240
Два байта текста дают архив того же размера. Заголовок файла занимает один блок, содержимое – второй, дальше идет маркер конца архива из двух нулевых блоков, а остаток записи добивается нулями до 10240.
Смысл этой механики описан в мануале GNU tar: записи на ленте разделялись промежутками, которые тратили место впустую, и чем крупнее запись, тем экономнее расходуется лента.
Двадцать блоков – это компромисс, выбранный под железо семидесятых.
Код на салфетке x Кусочки кода