8

假设您有两个要连接在一起的大文件(几 GB),但您的空闲磁盘空间非常少(比如说几百 MB)。也就是说,给定file1and file2,您希望得到一个文件,该文件是逐字节连接file1和在一起的结果,并删除原始文件。file2

你不能做明显的事情cat file2 >> file1; rm file2,因为在这两个操作之间,你会用完磁盘空间。

欢迎使用免费或非免费工具的任何和所有平台上的解决方案;这是我前几天在下载 Linux ISO 时想到的一个假设问题,由于无线故障,下载在中途中断。

4

15 回答 15

15

找出涉及磁盘扇区改组和文件链操作的巧妙解决方案所花费的时间:2-4 小时

获取/编写软件以进行就地复制和截断所花费的时间:2-20 小时

乘以 50 美元/小时程序员费率中位数:400-1200 美元

1TB USB 驱动器的成本:100-200 美元

理解“机会成本”一词的能力:无价的

于 2008-11-14T17:23:51.543 回答
9

我认为困难在于确定如何从原始文件中恢复空间。

我认为以下可能有效:

  1. 分配组合大小的稀疏文件。
  2. 将第二个文件末尾的 100Mb 复制到新文件的末尾。
  3. 截断第二个文件末尾的 100Mb
  4. 循环 2&3 直到完成第二个文件(将 2. 修改到目标文件中的正确位置)。
  5. 执行 2&3&4 但使用第一个文件。

这一切都依赖于稀疏文件支持和文件截断立即释放空间。

如果您真的想这样做,那么您应该调查该dd命令。哪个可以做复制步骤

另一个答案中的某人给出了一个不需要稀疏文件的简洁解决方案,但确实复制了 file2 两次:

  1. 将文件 2 末尾的 100Mb 块复制到新文件 3,以相反的顺序结束。随时截断文件 2。
  2. 将文件 3 末尾的 100Mb 块复制到文件 1 中,在文件 1 的末尾以原始顺序结束这些块。随时截断文件 3。
于 2008-11-14T16:59:11.483 回答
7

这比我的第一个答案略有改进。

如果您有 100MB 可用空间,请从第二个文件复制最后 100MB 并创建第三个文件。截断第二个文件,使其现在小 100MB。重复此过程,直到第二个文件完全分解为单独的 100MB 块。

现在,每个 100MB 文件都可以附加到第一个文件,一次一个。

于 2008-11-14T17:56:47.780 回答
4

有了这些限制,我希望您需要篡改文件系统;直接编辑文件大小和分配块。

换句话说,忘记打乱任何文件内容块,只需编辑有关这些文件的信息。

于 2008-11-14T16:53:32.413 回答
2

如果文件是高度可压缩的(即日志):

gzip file1

gzip file2

zcat file1 file2 | gzip > file3

rm file1

rm file2

gunzip file3
于 2009-07-24T23:04:34.527 回答
1

冒着听起来轻率的风险,您是否考虑过购买更大磁盘的选择?应该会更快...

于 2008-11-14T17:01:03.117 回答
1

效率不是很高,但我认为可以做到。

以追加模式打开第一个文件,然后将第二个文件中的块复制到它,直到磁盘几乎满了。对于第二个文件的其余部分,通过随机访问 I/O 将块从您停止的点复制回文件的开头。复制最后一个块后截断文件。重复直到完成。

于 2008-11-14T17:30:17.270 回答
1

好吧,为了理论上的娱乐,只有你保证不浪费你的时间实际去做:

  • 文件分片存储在磁盘上
  • 这些碎片链接成一条链

因此,您可以通过以下方式连接文件:

  • 将第一个文件的最后一段链接到最后一个文件的第一段
  • 更改第一个文件的目录条目以更改最后一个文件和文件大小
  • 删除最后一个文件的目录条目
  • 清理第一个文件的文件结束标记(如果有)
  • 请注意,如果第一个文件的最后一段仅部分填充,则必须将数据“向上”复制到最后一个文件的段以避免文件中间出现垃圾[感谢@Wedge!]

这将是最有效的:最少的更改、最少的复制、不需要备用磁盘空间。

现在去买一个USB驱动器;-)

于 2008-11-14T17:30:55.147 回答
1

显然,假设这是一个可能的答案,经济的答案是购买更多的存储空间。但它可能不是——嵌入式系统无法附加更多存储空间,甚至无法访问设备本身——比如飞行中的太空探测器。

如果您有一个稀疏文件系统,那么之前提出的基于稀疏文件系统的答案是好的(如果出现问题,它的破坏性除外!)。但是,如果你不这样做呢?

从文件 2 的末尾开始,将块复制到目标文件的开头,然后将它们反转。在每个块之后,您将源文件截断为未复制的长度。对文件 #1 重复此操作。

此时目标文件包含了所有向后的数据,源文件已经没有了。

从 tart 和目标文件的末尾读取一个块,将它们反转并将它们写入另一个来自的位置。向内翻转积木。

完成后,目标文件是源文件的串联。不需要稀疏文件系统,不需要弄乱文件系统。这可以在零字节空闲时执行,因为数据可以保存在内存中。

于 2008-11-14T17:45:07.053 回答
0

两个想法:

如果您有足够的物理 RAM,您实际上可以将第二个文件完全读入内存,将其删除,然后以附加模式将其写入第一个文件。当然,如果您在删除后但在完成写入之前断电,则您将永远丢失第二个文件的一部分。

暂时减少操作系统功能使用的磁盘空间(例如虚拟内存、“回收站”或类似的)。可能只在 Windows 上使用。

于 2008-11-14T17:10:40.180 回答
0

我怀疑这是对这个问题的直接回答。您可以将其视为解决问题的替代方法。

我认为可以将第二个文件视为第一个文件的第 2 部分。通常在 zip 应用程序中,我们会看到一个巨大的文件被分成多个部分。如果您打开第一部分,应用程序将自动考虑其他部分进行进一步处理。

我们可以在这里模拟同样的事情。正如@edg 指出的那样,修补文件系统将是一种方法。

于 2008-11-14T17:12:05.030 回答
0

你可以这样做:

head file2 --bytes=1024 >> file1 && tail --bytes=+1024 file2 >file2 

你可以根据你有多少额外的磁盘空间来增加 1024,然后重复这个直到所有的字节都被移动。

这可能是最快的方法(就开发时间而言)

于 2008-11-14T21:19:36.730 回答
0

您可以通过压缩整个文件系统来获得空间。我相信 NTFS 支持这一点,而且我确信有多种 *nix 文件系统支持它。它还有一个好处是,在复制文件后,您仍然会比开始时剩余更多的磁盘空间。

于 2008-11-14T21:36:40.363 回答
0

好的,稍微改变一下问题。磁盘上可能还有其他您不需要的东西,但您不知道它是什么或它在哪里。如果你能找到它,你可以删除它,然后也许你会有足够的额外空间。

为了找到这些“肿瘤”,无论是几个大的,还是很多小的,我都使用了一个小采样程序。从目录(或根)的顶部开始,它进行两次传递。在第 1 步中,它遍历目录树,将所有文件的大小相加得到总共 N 个字节。在第 2 步中,它再次遍历目录树,假装它正在读取每个文件。每次通过 N/20 字节时,它都会打印出它正在“读取”的文件的目录路径和名称。所以最终结果是 20 个深度路径名样本,均匀分布在目录下的所有字节中。

然后,只需查看该列表中出现很多您不需要的东西,然后将其吹走。

(这是我用于性能优化的采样方法的空间等效值。)

于 2008-11-19T04:33:55.103 回答
-1

“地图”

http://www.mjmwired.net/kernel/Documentation/filesystems/fiemap.txt

于 2010-02-03T03:07:51.640 回答