22

我已经在命令行提示符下在我的服务器上运行了两天的工作:

find data/ -name filepattern-*2009* -exec tar uf 2009.tar {} ;

它需要永远,然后是一些。是的,目标目录中有数百万个文件。(在散列良好的目录结构中,每个文件只有区区 8 个字节。)但只是运行......

find data/ -name filepattern-*2009* -print > filesOfInterest.txt

...只需要两个小时左右。以我的工作的速度,它不会在几个星期内完成.. 这似乎不合理。有没有更有效的方法来做到这一点? 也许使用更复杂的 bash 脚本?

第二个问题是“为什么我目前的方法这么慢?”

4

9 回答 9

25

一种选择是使用cpio生成 tar 格式的存档:

$ find data/ -name "filepattern-*2009*" | cpio -ov --format=ustar > 2009.tar

cpio本机使用来自标准输入的文件名列表,而不是顶级目录,这使其成为这种情况的理想工具。

于 2010-04-23T08:56:48.830 回答
21

如果您已经执行了创建文件列表的第二个命令,只需使用该-T选项告诉 tar 从保存的文件列表中读取文件名。运行 1 个 tar 命令与 N 个 tar 命令会好很多。

于 2010-04-23T14:34:36.210 回答
8

这是一个 find-tar 组合,可以在不使用 xargs 或 exec 的情况下执行您想要的操作(这应该会导致明显的加速):

tar --version    # tar (GNU tar) 1.14 

# FreeBSD find (on Mac OS X)
find -x data -name "filepattern-*2009*" -print0 | tar --null --no-recursion -uf 2009.tar --files-from -

# for GNU find use -xdev instead of -x
gfind data -xdev -name "filepattern-*2009*" -print0 | tar --null --no-recursion -uf 2009.tar --files-from -

# added: set permissions via tar
find -x data -name "filepattern-*2009*" -print0 | \
    tar --null --no-recursion --owner=... --group=... --mode=... -uf 2009.tar --files-from -
于 2010-04-23T10:05:33.157 回答
7

为此有 xargs:

find data/ -name filepattern-*2009* -print0 | xargs -0 tar uf 2009.tar

由于信息不多,很难猜测它为什么慢。目录的结构是什么,你使用什么文件系统,它是如何在创建时配置的。对于大多数文件系统来说,在单个目录中拥有数百万个文件是相当困难的情况。

于 2010-04-23T08:46:16.583 回答
3

要正确处理带有奇怪(但合法)字符(例如换行符,...)的文件名,您应该使用 find 的 -print0 将文件列表写入 filesOfInterest.txt:

find -x data -name "filepattern-*2009*" -print0 > filesOfInterest.txt
tar --null --no-recursion -uf 2009.tar --files-from filesOfInterest.txt 
于 2010-05-01T14:18:02.763 回答
2

您目前拥有的东西的方式是,每次找到文件时都会调用 tar 命令,这并不奇怪。与其花两个小时打印加上打开 tar 存档所需的时间,查看文件是否过期,然后将它们添加到存档中,您实际上是在将这些时间相乘。在将所有名称批处理在一起之后,您可能会更成功地调用 tar 命令一次,可能使用 xargs 来实现调用。顺便说一句,我希望你使用的是 'filepattern-*2009*' 而不是 filepattern-*2009*,因为星星会被不带引号的外壳扩展。

于 2010-04-23T08:47:04.757 回答
1

为此有一个实用程序,称为tarsplitter.

tarsplitter -m archive -i folder/*.json -o archive.tar -p 8

将使用 8 个线程将匹配 "folder/*.json" 的文件存档到 "archive.tar" 的输出存档中

https://github.com/AQUAOSOTech/tarsplitter

于 2018-11-20T17:13:20.480 回答
1

在使用 Python 的 tarfile 库找到更简单且可能更快的解决方案之前,我在 linux 上苦苦挣扎了很长时间。

  1. 使用 glob.glob 搜索所需的文件路径
  2. 以附加模式创建新存档
  3. 将每个文件路径添加到此存档
  4. 关闭存档

这是我的代码示例:

import tarfile
import glob
from tqdm import tqdm

filepaths = glob.glob("Images/7 *.jpeg")
n = len(filepaths)
print ("{} files found.".format(n))
print ("Creating Archive...")
out = tarfile.open("Images.tar.gz", mode = "a")
for filepath in tqdm(filepaths, "Appending files to the archive..."):
  try:
    out.add(filepath)
  except:
    print ("Failed to add: {}".format(filepath))

print ("Closing the archive...")
out.close()

查找 16222 个文件路径并创建存档总共花费了大约 12 秒,但是,这主要是通过简单地搜索文件路径来完成的。创建包含 16000 个文件路径的 tar 归档文件只用了 7 秒。使用一些多线程,这可能会更快。

如果您正在寻找多线程实现,我已经制作了一个并将其放置在此处:

import tarfile
import glob
from tqdm import tqdm
import threading

filepaths = glob.glob("Images/7 *.jpeg")
n = len(filepaths)
print ("{} files found.".format(n))
print ("Creating Archive...")
out = tarfile.open("Images.tar.gz", mode = "a")

def add(filepath):
  try:
    out.add(filepath)
  except:
    print ("Failed to add: {}".format(filepath))

def add_multiple(filepaths):
  for filepath in filepaths:
    add(filepath)

max_threads = 16
filepaths_per_thread = 16

interval = max_threads * filepaths_per_thread

for i in tqdm(range(0, n, interval), "Appending files to the archive..."):
  threads = [threading.Thread(target = add_multiple, args = (filepaths[j:j + filepaths_per_thread],)) for j in range(i, min([n, i + interval]), filepaths_per_thread)]
  for thread in threads:
    thread.start()
  for thread in threads:
    thread.join()

print ("Closing the archive...")
out.close()

当然,你需要确保 和 的值max_threadsfilepaths_per_thread优化的;创建线程需要时间,因此对于某些值,时间实际上可能会增加。最后要注意的是,由于我们使用的是附加模式,如果一个新存档尚不存在,我们将自动创建一个具有指定名称的新存档。但是,如果一个已经存在,它只会添加到预先存在的存档中,而不是重置它或创建一个新存档。

于 2020-08-10T18:48:44.093 回答
-2

最简单的(创建存档后也删除文件):

find *.1  -exec tar czf '{}.tgz' '{}' --remove-files \;
于 2013-07-13T20:14:13.647 回答