在不读取文件末尾的情况下向文件中间添加内容

7

我在unix.stackexchange上阅读了许多关于如何在不需要创建临时文件的情况下添加或删除文件中的行的问题/答案。

https://unix.stackexchange.com/questions/11067/is-there-a-way-to-modify-a-file-in-place?lq=1

似乎所有这些答案都需要至少读取文件直到末尾,如果输入是一个大文件,则可能会耗费时间。有没有什么方法可以解决这个问题?我希望文件系统像链表一样实现...所以应该有一种方法来达到所需的“行”,然后只需添加内容(链表中的节点)。我该怎么做?
我的想法是否正确?或者我有什么遗漏吗?
附注:我需要在'C'中完成此操作,不能使用任何shell命令。

文件并不是作为链表来实现的,所以没有一种简单的方法可以将数据插入到文件中间。参见SO 10467711获取处理在文件中间插入数据的代码,但请注意它最终会将插入点后面的所有数据复制到正确的新位置。 - Jonathan Leffler
4个回答

11

自Linux 4.1起,fallocate(2)支持FALLOC_FL_INSERT_RANGE标志,允许在文件中间插入给定长度的空洞而不重写后续数据。但是,它具有一定的限制:必须在文件系统块边界处插入空洞,插入的空洞大小必须是文件系统块大小的倍数。另外,在4.1版中,此功能仅由XFS文件系统支持,在4.2版中添加了对Ext4的支持。

对于所有其他情况,仍然需要重写文件的其余部分,如其他答案所示。


谢谢!您的回答是否适用于我的问题:http://unix.stackexchange.com/q/281652/9689?我已经在那里引用了它,但如果您将其作为自己的答案添加,我将很高兴将其标记为答案并删除我的引用。 :) - Grzegorz Wierzowiecki

9
简短的答案是,可以直接修改文件内容,但不行在文件中间添加或删除内容。
UNIX文件系统使用inode指针结构实现,该结构指向整个数据块。文本文件的每一行都不知道它与前一行或后一行的关系,它们只是在块内相邻。要在这两行之间添加内容需要将其余内容向下移动,将一些数据推入下一个块,进而必须移动到下一个块中,如此等等。
在C中,您可以打开文件进行更新并读取其内容,并覆盖其中一些内容,但我不认为有任何方法(即使理论上)可以在中间插入新数据或删除数据(除非用null覆盖)。

谢谢,你说的没错。但是很遗憾我只能接受一个答案。所以我会通过投票来决定。 - user763410
文件系统不允许碎片化吗?例如,即使在某些情况下,ext4也可能会出现碎片化。 - Mateen Ulhaq

4
您可以直接修改文件,例如使用dd命令。
$ echo Hello world, how are you today? > helloworld.txt
$ cat helloworld.txt
Hello world, how are you today?
$ echo -n Earth | dd of=helloworld.txt conv=notrunc bs=1 seek=6
$ cat helloworld.txt
Hello Earth, how are you today?

问题在于,如果您的更改还改变了长度,它将不能完全正确地工作:

$ echo -n Joe | dd of=helloworld.txt conv=notrunc bs=1 seek=6
Hello Joeth, how are you today?
$ echo -n Santa Claus | dd of=helloworld.txt conv=notrunc bs=1 seek=6
Hello Santa Clausare you today?

当你改变长度时,你必须重新编写文件,如果没有完全重新编写,那么从你所做的更改点开始重新编写。

在C语言中,这与使用dd相同。你打开文件,寻找位置并写入。


0

你可以以读写模式打开一个文件。你可以读取文件(或使用“seek”跳转到想要的位置,如果你知道它),然后写入文件,但是你会覆盖这里的数据(这不是插入)。 然后你可以选择从你最后写入的位置截断文件,或者保留在你写入点之后的所有剩余数据而不读取它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接