19

假设我有 2 个文件,每个文件大小为 100G。我想将它们合并为一个,然后将它们删除。在linux中我们可以使用

猫文件 1 文件 2 > final_file

但这需要读取 2 个大文件,然后写入一个更大的文件。是否可以只将一个文件附加到另一个文件,这样就不需要 IO?由于文件的元数据包含文件的位置和长度,我想知道是否可以更改文件的元数据来进行合并,所以不会发生 IO。

4

3 回答 3

30

您可以合并两个文件而不将一个文件写入另一个文件吗?

只是在晦涩的理论中。由于磁盘存储始终基于块,因此文件系统将内容存储在块边界上,如果第一个文件在块边界上完美结束,您只能将一个文件附加到另一个文件而无需重写。有一些罕见的文件系统配置使用 tail packing,但这只有在第一个文件已经使用前一个文件的尾部块时才有帮助。

除非出现这种完美的情况,或者您的文件系统能够在文件中间标记部分块(我从未听说过),否则这将不起作用。只是为了解决边缘情况,除了更改内核接口来进行这样的调用之外,别无他法(re: Link to a specific inode

我们可以使这比将两个文件的大小都增加一倍更好吗?

的,我们可以使用 append ( >>) 操作来代替。

cat file2 >> file1

这仍然会导致使用file2两倍以上消耗的所有空间,直到我们可以将其删除。

我们可以避免使用额外的空间吗?

没有。除非有人带着我不知道的东西回来,否则你基本上不走运。可以截断文件,忘记它的结尾的存在,但是没有办法忘记开头的存在,除非我们直接修改 inode 并不得不改变内核到文件系统的接口,因为那是绝对不是 POSIX 操作。

一次写一点,然后删除我们写的内容怎么样?

没有了。由于我们无法切断文件的开头,因此我们必须重写从感兴趣点一直到文件结尾的所有内容。这对于 IO 来说是非常昂贵的,并且只有在我们已经读取了一半文件之后才有用。

稀疏文件呢?

也许!稀疏文件允许我们存储一长串零,而不会占用几乎那么多空间。如果我们file2要从末尾开始读取大块,我们可以将这些块写入file1. file1会立即看起来(和读取)好像它与两者的大小相同,但在我们完成之前它会被破坏,因为我们没有写入的所有内容都将充满零。

解释这一切本身就是另一个答案,但如果您可以进行备用分配,您将能够仅使用您的块读取大小 + 一点额外的磁盘空间来执行此操作。有关文件中间稀疏块的参考,请参阅http://lwn.net/Articles/357767/或进行涉及术语的搜索,SEEK_HOLE.

为什么这是“也许”而不是“是”?两部分:您必须编写自己的工具(至少我们在正确的站点上),并且文件系统和其他类似进程并不普遍尊重稀疏文件。幸运的是,您可能不必担心其他进程会尊重您的文件,但您将不得不担心设置正确的标志并确保您的文件系统适合。最后,您仍将读取和重写 的长度file2,这不是您想要的。但是,此方法确实意味着您可以仅使用少量磁盘空间进行追加,而不是至少使用2*file2大量空间。

于 2012-11-16T06:01:47.543 回答
7

你可以这样做

cat file2 >> file1

file1 将成为完整内容。

于 2012-11-16T05:48:05.323 回答
1

不,不可能通过处理元数据来合并(在 Linux 上)两个大文件。

也许您可能会考虑为您的工作使用某种数据库。

正如 Alexandre 所注意到的,您可以将一个大文件附加到另一个文件,但这仍然需要大量数据复制。

于 2012-11-16T05:47:56.910 回答