6

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

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

似乎所有这些答案都需要至少阅读到文件末尾,如果输入是一个大文件,这可能会很耗时。有没有解决的办法?我希望文件系统能够像链表一样实现......所以应该有一种方法可以达到所需的“行”,然后只需添加东西(链表中的节点)。我该怎么做呢?

我这样想对吗?还是我错过了什么?

Ps:我需要在'C'中完成这个并且不能使用任何shell命令。

4

4 回答 4

9

简短的回答是,的,可以就地修改文件的内容,但是,不可能在文件中间删除或添加内容。

UNIX 文件系统是使用指向整个数据块的inode 指针结构实现的。文本文件的每一行并不“知道”它与上一行或下一行的关系,它们只是在块内彼此相邻。要在这两行之间添加内容,需要在块内进一步“向下”移动以下所有内容,将一些数据推送到下一个块中,而下一个块又必须移动到下一个块中,等等。

在 C 中,您可以打开一个文件进行更新并读取其内容,并覆盖一些内容,但我不相信(甚至理论上)有任何方法可以在中间插入新数据或删除数据(除了覆盖它带空值。

于 2013-06-19T18:15:38.963 回答
9

从 Linux 4.1 开始,fallocate(2)支持该FALLOC_FL_INSERT_RANGE标志,它允许在文件中间插入一个给定长度的孔,而无需重写以下数据。但是,它是相当有限的:必须在文件系统块边界处插入孔,并且插入的孔的大小必须是文件系统块大小的倍数。此外,在 4.1 中,此功能仅受 XFS 文件系统支持,在 4.2 中添加了对 Ext4 的支持。

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

于 2015-10-26T05:31:04.263 回答
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 中,这与 with 相同dd。你打开文件,你寻找,你写。

于 2013-06-19T18:33:21.977 回答
0

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

于 2014-08-18T16:24:28.253 回答