我在使用 Ubuntu 16.04。
我有一个文件夹,里面有很多文本文件(差不多 12k)。我需要将它们全部上传到一个接受.tar.gz
上传的网站,然后自动解压,但每个文件的大小限制为 10MB(10000KB)(因此每个文件都必须单独解压)。如果我将tar.gz
所有这些文件都解压,则生成的文件大约为 72MB。
我想要做的是创建八个.tar.gz
文件,每个文件的大小/尺寸(严格)小于 10000KB。
或者,可以假设上述所有文件都具有大致相同的尺寸,因此我想创建八个.tar.gz
文件,每个文件的文件数量大致相同。
我怎样才能完成这两项任务?
我完全可以接受包含 GUI、CLI 或脚本的解决方案。我并不追求速度,我只需要完成它。
答案1
完全虽然它是一个拼凑的、快速粗略的草图,但在包含 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)
如何使用
- 将其保存为空文件
compress_split.py
- 在 head 部分,设置要压缩的文件数量。实际上,总会有一个文件来处理剩下的几个“剩余文件”。
使用包含文件的目录作为参数来运行它:
python3 /path/tocompress_split.py /directory/with/files/tocompress
编号.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)
跑步:
python3 /path/tocompress_split.py /directory/with/files/tocompress chunksize
...其中,chunksize 是输入对于 tar 命令。
这篇文章包含了@DavidFoerster 建议的改进。谢谢很多!
答案2
纯 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
解释
files=(*)
:将文件列表(如果存在,也包括目录,更改为files=(*.txt)
以仅获取带有txt
扩展名的内容)保存在数组中$files
。num=$((${#files[@]}/8));
:${#files[@]}
是数组中元素的数量$files
。这$(( ))
是 bash 进行算术运算的(有限方式)。因此,此命令设置$num
为文件数除以 8。k=1
:仅用于命名 tarball 的一个计数器。for ((i=0; i<${#files[@]}; i+=$num)); do
:迭代数组的值。$i
初始化为0
(数组的第一个元素)并增加$num
。此过程持续到我们遍历完所有元素(文件)。tar cvzf files$i.tgz -- ${files[@]:$i:$num}
:在 bash 中,您可以使用 来获取数组切片(数组的一部分)${array[@]:start:length}
,因此${array[@]:2:3}
将从第二个元素开始返回三个元素。在这里,我们获取一个从 的当前值开始的切片,长度$i
为$num
个元素。--
如果您的任何文件名可以以 开头,则需要-
。((k++))
: 增量$k