Как к tar.gz много файлов подобного размера в несколько архивов с пределом размера

Я нахожусь на Ubuntu 16.04.

У меня есть папка с большим количеством текстовых файлов (почти 12k). Я должен загрузить их всех на веб-сайт, который принимает .tar.gz загрузки и затем распаковывают их автоматически, но имеют предел 10 МБ (10000 КБ) на файл (так в особенности, каждый файл должен быть распакован самостоятельно). Если я tar.gz все эти файлы получающийся файл имеют приблизительно 72 МБ.

То, что я хотел бы сделать, должно создать восемь .tar.gz файлы, каждый размер / размер (строго) меньший, чем 10000 КБ.

С другой стороны, можно предположить, что все файлы выше имеют приблизительно тот же размер, таким образом, я хотел бы создать восемь .tar.gz файлы с более или менее той же суммой файлов каждый.

Как я могу сделать какую-либо из этих двух задач?

Все замечательно с решением, которое включает GUI, CLI или сценарии. Я не ищу скорость здесь, мне просто нужен в сделанный.

11
задан 6 November 2016 в 21:45

2 ответа

Полностью пэчворк и быстрый, грубый эскиз, как это, но протестированный на каталоге с 3 000 файлов, сценарий ниже сделал чрезвычайно быстрое задание:

#!/usr/bin/env python3
import subprocess
import os
import sys

splitinto = 2

dr = sys.argv[1]
os.chdir(dr)

files = os.listdir(dr)
n_files = len(files)
size = n_files // splitinto

def compress(tar, files):
    command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
    proc = subprocess.Popen(command, stdin=subprocess.PIPE)
    with proc:
        proc.stdin.write(b'\0'.join(map(str.encode, files)))
        proc.stdin.write(b'\0')
    if proc.returncode:
        sys.exit(proc.returncode)

sub = []; tar = 1
for f in files:
    sub.append(f)
    if len(sub) == size:
        compress(tar, sub)
        sub = []; tar += 1

if sub:
    # taking care of left
    compress(tar, sub)

Как использовать

  • Сохраните его в пустой файл как compress_split.py
  • В главном разделе, определенном номер файлов для сжатия в. На практике всегда будет еще один для заботы об оставлении немногими "левыми верхними мячами".
  • Выполните его с каталогом с Вашими файлами как аргумент:

    python3 /path/tocompress_split.py /directory/with/files/tocompress
    

пронумерованный .tar.gz файлы будут созданы в том же каталоге как, где файлы.

Объяснение

Сценарий:

  • списки все файлы в каталоге
  • CD в каталог для предотвращения добавления информации о пути в файл tar
  • прочитывает список файлов, группируя их подразделением набора
  • сжимает sub группу (группы) в пронумерованные файлы

Править

Автоматически создайте блоки размером в МБ

Более сложный должен использовать макс. - размер (в МБ) блоков как (второй) аргумент. В сценарии ниже, блоки записаны в сжатый файл, как только блок достигает (передает) порог.

Так как сценарий инициирован блоками, превысив порог, это будет только работать, если размер (всех) файлов будет существенно меньшим, чем размер блока.

Сценарий:

#!/usr/bin/env python3
import subprocess
import os
import sys

dr = sys.argv[1]
chunksize = float(sys.argv[2])
os.chdir(dr)

files = os.listdir(dr)
n_files = len(files)

def compress(tar, files):
    command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
    proc = subprocess.Popen(command, stdin=subprocess.PIPE)
    with proc:
        proc.stdin.write(b'\0'.join(map(str.encode, files)))
        proc.stdin.write(b'\0')
    if proc.returncode:
        sys.exit(proc.returncode)

sub = []; tar = 1; subsize = 0
for f in files:
    sub.append(f)
    subsize = subsize + (os.path.getsize(f)/1000000)
    if subsize >= chunksize:
        compress(tar, sub)
        sub = []; tar += 1; subsize = 0

if sub:
    # taking care of left
    compress(tar, sub)

Работать:

python3 /path/tocompress_split.py /directory/with/files/tocompress chunksize

... где chunksize является размером входа для команды tar.

В этом включены предложенные улучшения @DavidFoerster.Большое спасибо!

9
ответ дан 23 November 2019 в 04:01

Чистый подход оболочки:

files=(*); 
num=$((${#files[@]}/8));
k=1
for ((i=0; i<${#files[@]}; i+=$num)); do 
    tar cvzf files$k.tgz -- "${files[@]:$i:$num}"
    ((k++))
done

Объяснение

  • files=(*) : сохраните список файлов (также каталоги, если кто-либо присутствует, изменяется на files=(*.txt) получить только вещи с a txt расширение) в массиве $files.
  • num=$((${#files[@]}/8)); : ${#files[@]} число элементов в массиве $files. $(( )) (ограниченный) способ удара сделать арифметику. Так, это наборы команд $num к количеству файлов, разделенных на 8.
  • k=1 : просто в противоречии с именем tarballs.
  • for ((i=0; i<${#files[@]}; i+=$num)); do : выполните итерации по значениям массива. $i инициализируется в 0 (первый элемент массива) и увеличенный $num. Это продолжается, пока мы не прошли все элементы (файлы).
  • tar cvzf files$i.tgz -- ${files[@]:$i:$num} : в ударе можно получить часть массива (часть массива) использование ${array[@]:start:length}, Так ${array[@]:2:3} возвратит три элемента, начинающие со второго. Здесь, мы берем часть, которая запускается в текущем значении $i и $num элементы долго. -- необходим в случае, если любые из Ваших имен файлов могут запуститься с a -.
  • ((k++)) : инкремент $k
6
ответ дан 23 November 2019 в 04:01

Другие вопросы по тегам:

Похожие вопросы: