我有一个程序,它接受用户提供的数据(整数、浮点数和字符串)并将其写入文本文件。现在我必须更新部分写入的数据。
例如:
在文件的第 4 行,我想更改前 2 个单词(有 anint
和 a float
)。我怎样才能做到这一点?
有了我发现的信息,fseek()
可以fputs()
使用,但我不知道如何到达特定线路。
(解释代码将不胜感激,因为我是 C 语言的初学者)
您不能在文件中“插入”字符。您将必须创建程序,该程序将读取整个文件,然后在插入新文件之前复制部分,您的版本,文件的其余部分。
您确实需要阅读所有文件,并忽略不需要的内容。
fseek
并不是很有用:它将文件定位在某个字节偏移量(相对于文件的开头或结尾)并且不知道行边界。
实际上,文件中的行是一个定义不明确的概念。通常,一行是由换行符 ( ) 结束的字节序列(不同于换行符'\n'
)。某些操作系统(Windows、MacOSX)以特殊方式读取文本文件(例如,真实文件包含\r\n
以结束每一行,但 C 库给您的错觉是您已阅读\n
)。
在实践中,您可能特别想(或可能)使用行输入例程。getline
fgets
如果你使用getline
你应该关心free
-ing 行缓冲区。
如果您的文本文件具有非常规则的结构,您可能会fscanf
在不关心行边界的情况下获取数据(忽略需要跳过的内容)。
如果您想绝对使用fseek
(这是一个错误),则必须读取该文件两次:第一次记住每行的开始(或结束)位置,第二次记住fseek
该行的开头。不过,这对更新不起作用,因为您不能在文件中间插入字节。
而在实践中,最昂贵的操作是实际的磁盘读取。缓冲(部分由内核和<stdio.h>
函数完成,部分由您在处理行时完成)可以忽略不计。
当然,您不能更改文件中的某些行。如果您需要这样做,请处理输入文件,生成一些输出文件(包含修改后的输入)并在完成后重命名。
顺便说一句,您可能对GDBM等索引文件感兴趣......甚至对SqlLite、MariaDb、mongodb等数据库感兴趣......并且您可能对JSON或YAML等标准文本序列化格式感兴趣(两者都有很多库,即使对于 C 来说,也要处理它们)。
fseek()
用于每个数据记录具有相同大小的随机访问文件。通常数据是二进制的,而不是文本的。
要解决您的特定问题,您需要一次阅读一行以找到要更改的行。进行更改的一个简单解决方案是将这些行写入临时文件,将更改写入同一个临时文件,然后跳过原始文件中要更改的部分并将重置复制到临时文件。最后关闭原文件,将临时文件复制到其中,删除临时文件。
话虽如此,我建议您了解有关随机访问文件的更多信息。这些在存储所有相同大小的记录时非常有用。如果您可以控制创建原始文件,这些可能更适合您当前的目的。