2 способа упаковки Big Data в ручную кладь
Проблема передачи больших данных, их сжатия и разбиения набила оскомину для data scientist-ов. В этой статье поделюсь методами решения этих задач.
Рассмотрим кейс передачи данных на сервер, когда последовательность действий приобретает такой вид - архивация набора файлов, разбиение архива на куски фиксированного размера, передача, сборка на целевом сервере в один файл и его распаковка.
Изложим два способа.
С использованием утилит
Создать архив из папки можно командой:
zip -r архив.zip папка_файл
Чтобы разбить на части с верхней границей размера набираем:
zip цельный_архив.zip --out разделенный_архив.zip -s размер
Например, так указывается размер не более 50 Мб или 100 Кб - 50m и 100k (также имеются сокращения g - ГБ, t - ТБ)
Эти команды можно объединить:
zip -r -s размер разделенный_архив.zip папка_файл
Для сборки на сервере частей архива в один применяется команда:
zip -s 0 основной_файл_разделенного_архива.zip --out имя_собранного_архива.zip
Распаковка может пройти командой unzip, если не возникнет проблем с кодировкой:
unzip имя_архива.zip
В противном случае (например, так как у меня названия файлов содержали символы кириллицы возникло исключение - Illegal byte sequence) используем команду:
ditto -V -x -k --sequesterRsrc --rsrc имя_архива.zip имя_папки_с_результатом
С использование Python
Те же действия можно произвести с помощью Python. Для этого нужно внимательно изучить рекомендации изложенные в этом материале.
Коротко, вам потребуются два модуля - zipfile и filesplit, их классы ZipFile и Filesplit, а также методы с "говорящими" названиями. Приведу разбитый на две части код для реализации указанной в начале статьи цели по передаче папки на сервер (dir_source).
Операции на локальных машине (архивирование и разбиение на части):
import zipfile import os from fsplit.filesplit import Filesplit dir_source = 'source' arch_fn = 'data' dir_pieces = 'pieces' with zipfile.ZipFile(f'{arch_fn}.zip', 'w', compression=zipfile.ZIP_DEFLATED) as zip_f: for folder, subfolders, filenames in os.walk(dir_source): for filename in filenames: zip_f.write(os.path.join(folder, filename)) print(f'создан архив с именем {arch_fn}.zip') zip_f = zipfile.ZipFile(f'{arch_fn}.zip') for fn in zip_f.namelist(): info = zip_f.getinfo(fn) print(f'файл - {fn}, размер - {info.file_size}, сжатый размер - {info.compress_size}') fs = Filesplit() if not os.path.exists(dir_pieces): os.mkdir(dir_pieces) def split_cb(f, s): print("file: {0}, size: {1}".format(f, s)) fs.split(file=f'{arch_fn}.zip', split_size=50000, output_dir=dir_pieces, callback=split_cb) os.remove(f'{arch_fn}.zip')
Операции на сервере (сборка и извлечение):
import zipfile import os from fsplit.filesplit import Filesplit import shutil fs = Filesplit() dir_pieces = 'pieces' arch_fn = f'{dir_pieces}/data' dir_out = 'output' def merge_cb(f, s): print("file: {0}, size: {1}".format(f, s)) fs.merge(input_dir=dir_pieces, callback=merge_cb) zip_f = zipfile.ZipFile(f'{arch_fn}.zip') zip_f.extractall(dir_out) shutil.rmtree(dir_pieces)