如何将许多类似大小的文件 tar.gz 压缩到多个具有大小限制的档案中

dad*_*x86 11 gui command-line archive tar

我在 Ubuntu 16.04 上。

我有一个文件夹,里面有很多文本文件(将近 12k)。我需要将它们全部上传到一个接受.tar.gz上传然后自动解压缩的网站,但每个文件的限制为 10MB (10000KB)(所以特别是每个文件都必须自己解压缩)。如果我tar.gz所有这些文件,生成的文件大约为 72MB。

我想做的是创建八个.tar.gz文件,每个文件的大小/维度(严格)小于 10000KB。

或者,可以假设上述所有文件的尺寸大致相同,因此我想创建八个.tar.gz文件,每个文件的文件数量或多或少。

我怎样才能完成这两项任务中的任何一项?

我对涉及 GUI、CLI 或脚本的解决方案非常满意。我不是在这里寻找速度,我只需要完成它。

Jac*_*ijm 9

完全拼凑而成,并且是一个快速、粗略的草图,但在包含 3000 个文件的目录上进行了测试,下面的脚本完成了非常快的工作:

#!/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)
Run Code Online (Sandbox Code Playgroud)

如何使用

  • 将它保存到一个空文件中 compress_split.py
  • 在 head 部分,设置要压缩到的文件数。在实践中,总会有一个人来处理剩下的几个“剩饭剩菜”。
  • 使用您的文件作为参数的目录运行它:

    python3 /path/tocompress_split.py /directory/with/files/tocompress
    
    Run Code Online (Sandbox Code Playgroud)

编号.tar.gz文件将在与文件所在的目录相同的目录中创建。

解释

剧本:

  • 列出目录中的所有文件
  • cd 进入目录以防止将路径信息添加到 tar 文件
  • 读取文件列表,按设置的分区对它们进行分组
  • 将子组压缩为编号文件

编辑

以 mb 为单位按大小自动创建块

更复杂的是使用块的最大大小(以 mb 为单位)作为(第二个)参数。在下面的脚本中,一旦块达到(通过)阈值,块就会被写入压缩文件。

由于脚本是由块触发的,超过阈值,因此只有(所有)文件的大小远小于块大小时,这才会起作用。

剧本:

#!/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)
Run Code Online (Sandbox Code Playgroud)

跑步:

python3 /path/tocompress_split.py /directory/with/files/tocompress chunksize
Run Code Online (Sandbox Code Playgroud)

...其中 chunksize 是tar 命令的输入大小。

在这一方面,包括@DavidFoerster 提出的改进建议。感谢了很多


ter*_*don 6

纯 shell 方法:

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

解释

  • files=(*):在数组中保存文件列表(如果存在目录,也可以更改为files=(*.txt)仅获取带有txt扩展名的内容)$files
  • num=$((${#files[@]}/8));:${#files[@]}是数组中的元素数$files。这$(( ))是 bash 的(有限的)算术方式。因此,此命令设置$num为文件数除以 8。
  • k=1 : 只是一个用于命名 tarball 的计数器。
  • for ((i=0; i<${#files[@]}; i+=$num)); do: 迭代数组的值。$i0(数组的第一个元素)处初始化并递增$num。这种情况一直持续到我们遍历完所有元素(文件)。
  • tar cvzf files$i.tgz -- ${files[@]:$i:$num}: 在 bash 中,您可以使用 获取数组切片(数组的一部分)${array[@]:start:length},因此${array[@]:2:3}将从第二个元素开始返回三个元素。在这里,我们正在取一个从 的当前值开始$i并且$num元素长的切片。在--需要的情况下,你的任何文件名可以用一个开始-
  • ((k++)) : 增量 $k