【问题标题】:Split file occupying the same memory space as source file拆分文件占用与源文件相同的内存空间
【发布时间】:2011-09-07 23:06:37
【问题描述】:

我有一个文件,大小为 100MB。我需要将它分成(例如)4 个不同的部分。 假设第一个文件从 0-20MB,第二个 20-60MB,第三个 60-70MB,最后一个 70-100MB。 但我不想安全拆分 - 分成 4 个输出文件。我想就地做。所以输出文件应该使用这个源文件所占用的硬盘上的同一个位置,并且字面意思分割它,而不是复制(所以在分割的那一刻,我们应该松开原始文件)。

换句话说,输入文件就是输出文件。

这可能吗?如果可以,怎么做?

我在想也许可以手动向文件系统添加一条记录,文件 A 从这里开始,到这里结束(在另一个文件的中间),执行 4 次,然后删除原始文件。但为此,我可能需要管理员权限,并且可能对文件系统不安全或不健康。

编程语言无关紧要,我只是对它感兴趣。

【问题讨论】:

  • 或许可以做到,当然不明智。
  • 我之所以要这样做,是因为性能和磁盘空间。如果文件为 20GB,则“以正确的方式”拆分文件将需要另外 20GB 和大量时间才能完成。 “就地”拆分需要一秒钟的时间,结果是一样的,尤其是当我处理的数据相关性较低时。
  • 除非你破坏了文件系统,否则你会花一整天的时间来修复它:)
  • 理论上,这相当简单。就 inode(NTFS:文件记录,HFS+:??)而言,第一个 inode 包含文件大小和属于该文件的块的(开头)列表。理想情况下,您只需更改 4 个 inode。但我怀疑你会那么容易逃脱。您需要仔细研究 NTFS 和 HFS+ 的内部结构。
  • 可以按照常规方式拆分大文件,而无需使用等于整个文件的额外空间。您可以将 last 块复制到新文件,然后使用truncate() 从输入文件中删除该部分,然后重复。输入文件以开头的块结束。这只需要与块大小相等的额外空间。使用的时间几乎与天真的方法一样多,但空间更少。

标签: file split filesystems


【解决方案1】:

这个想法并不像某些 cmets 所描绘的那么疯狂。肯定有可能拥有一个支持此类重新解释操作的文件系统 API(可以肯定的是,所需的拆分可能与块边界不完全对齐,但您可以仅重新分配那几个边界块并仍然节省大量临时空间)。

没有一个通用的文件系统抽象层支持这一点;但请记住,它们甚至不支持像“插入模式”这样合理的东西(当您将内容插入文件中间时,它只会重写一两个块,而不是所有块),只支持覆盖和追加模式.其原因在很大程度上是历史性的,但当前模型是如此根深蒂固,以至于更丰富的 API 不太可能很快变得普遍。

【讨论】:

  • 谢谢!我最初也是这么想的,世界是建立在疯狂的想法之上的 :) 我认为一些专有的实现允许这样的拆分操作,例如硬件录像机 (PVR)。他们中的许多人支持分割录制的视频文件,对巨大的高清文件执行的操作只需要几秒钟。很遗憾没有用于此类操作的 API :( 我会给你一个 +1,但我还没有 +15 的声誉。
【解决方案2】:

正如我在 SuperUser 上的 this question 中解释的那样,您可以使用 Tom Zych 在他的评论中概述的技术来实现这一点。

bigfile="mybigfile-100Mb"
chunkprefix="chunk_"
# Chunk offsets
OneMegabyte=1048576
chunkoffsets=(0 $((OneMegabyte*20)) $((OneMegabyte*60)) $((OneMegabyte*70)))

currentchunk=$((${#chunkoffsets[@]}-1))
while [ $currentchunk -ge 0 ]; do
    # Print current chunk number, so we know it is still running.
    echo -n "$currentchunk "
    offset=${chunkoffsets[$currentchunk]}
    # Copy end of $archive to new file
    tail -c +$((offset+1)) "$bigfile" > "$chunkprefix$currentchunk"
    # Chop end of $archive
    truncate -s $offset "$archive"
    currentchunk=$((currentchunk-1))
done

您需要为脚本提供每个块的起始位置(偏移量以字节为单位,零表示从bigfile 的第一个字节开始的块),按升序排列,如第五行。

如有必要,使用 seq 自动化它:以下命令将给出一个块偏移量,其中一个块在 0,然后一个从 100k 开始,然后在 1--10Mb 范围内每兆字节一个,(注意 -1 表示last 参数,因此它被排除)然后每两兆字节一个块,范围为 10--20Mb。

OneKilobyte=1024
OneMegabyte=$((1024*OneKilobyte))
chunkoffsets=(0 $((100*OneKilobyte)) $(seq $OneMegabyte $OneMegabyte $((10*OneMegabyte-1))) $(seq $((10*OneMegabyte-1)) $((2*OneMegabyte)) $((20*OneMegabyte-1))))

查看你设置了哪些块:

for offset in "${chunkoffsets[@]}"; do echo "$offset"; done
0
102400
1048576
2097152
3145728
4194304
5242880
6291456
7340032
8388608
9437184
10485759
12582911
14680063
16777215
18874367
20971519

这种技术的缺点是它至少需要最大可用块的大小(不过,您可以通过制作更小的块并将它们连接到其他地方来缓解这种情况)。此外,它会复制所有数据,因此远非即时。

至于一些硬件录像机 (PVR) 设法在几秒钟内分割视频这一事实,它们可能只存储每个视频(也称为章节)的偏移量列表,并将这些作为独立的视频显示在其用户界面中。

【讨论】:

    猜你喜欢
    • 2017-11-16
    • 2016-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    • 2021-02-28
    • 1970-01-01
    • 2017-03-10
    相关资源
    最近更新 更多