我有一个 datas.txt 文件:
格式:姓氏债务偿还
bir bir 100 2
iki iki 200 2
eray alakese 100 5
john doe 2000 10
我正在学习C和我只知道简单的文件功能(fscanf,fprinf,fopen等)
我会
scanf
询问用户名和姓氏,然后将其分配给名称和姓氏变量。fscanf(file, "%s %s %d %d", name, surname, &debt, &payment);
)这是我的源代码。
scanf("%s", &name);
scanf("%s", &surname);
file = fopen("datas.txt", "r");
/* this fscanf() is working as expected. There is no problem. */
fscanf(file, "%s %s %d %d", name, surname, &debt, &payment);
/* modify and delete actions here */
fclose(file);
示例:
答案 0 :(得分:3)
您不能删除/修改[*]文本文件的各行;唯一的解决方案是1)创建一个新的临时文件,2)复制内容,但不包括你想要修改/删除的行,3)输出修改后的行,4)复制原始文件的其余部分,5)用临时文件替换旧文件。
[*]仅当修改的行与原始行具有相同的长度时才可以进行修改。
编辑:PS:使用fgets,然后使用sscanf(或其他一些标记线的方式)将为您带来更多的悲伤。
答案 1 :(得分:1)
这有点难,因为从Unix继承的C文件模型(它们主要是代码开发的)实际上并没有将文件定义为行列表。相反,它将一行定义为以换行符终止的字节串,将文件(粗略地)定义为可能有限长度的存储字节串,您可以跳到不同的部分。这是相当模糊的,但请耐心等待。
当我们尝试将我们的想法 - “修改此行”,“删除该行” - 转换为文件操作时,问题变得更加清晰。我们可以通过在换行符处停止读取一行,但根本没有命令将其切割成多个部分;只设置结束(ftruncate())。因此,要更改行的大小,我们需要复制其后的所有数据。它可以完成,但重新创建文件通常更容易。比较实现memmove()的细微之处。
执行此操作的传统方法有两种变体,具体取决于您可以忍受的副作用。
一种是将更新后的版本写入另一个文件,然后将其重命名()到位。这样做的好处是,新文件将在您放置到位时完成,但缺点是它可能与旧文件不完全匹配,只要权限等,并且它将不会被其他程序看到已经把旧的打开了。如果两个程序像这样修改文件,则它是竞争条件,因为其中一个更改被另一个更改。
另一种方法是完全加载数据并将修改后的版本写入到位。这意味着文件本身保留在适当的位置,权限和所有权限,但是当您保存它是新旧内容的混合时会有一段时间。文本编辑器倾向于这样做,通常将旧内容保存为单独的文件,以防出现问题。
还有管理副作用的工具,例如版本化文件系统,文件锁定,甚至为并行更改准备的库(想到metakit)。大多数时候我们都会使用已经存在的工具,比如sed -i。
答案 2 :(得分:0)
为了删除或改变一行,你必须" shift"一切都在它之后。例如,请考虑以下两个文件:
bir bir 100 2 bytes 0-14
iki iki 200 2 bytes 15-29
eray alakese 100 5 bytes 30-49
john doe 2000 10 bytes 50-67
和
bir bir 100 2 bytes 0-14
iki iki 200 2 bytes 15-29
john doe 2000 10 bytes 30-57 <-- byte offsets have changed
这当然是可以做到的,但一般来说支持起来非常复杂(你必须做很多寻求和讲述)。更常用的方法是有效地复制文件:从输入文件读入并将所有内容打印到输出文件,进行所需的修改。 (例如,要删除&#34;删除&#34;一行,您只是不打印该行。)然后,最后,在关闭这两个文件后,您将重命名&#34;输出文件覆盖输入文件。这是命令行实用程序(如sed
和perl
)在指示修改文件&#34;就地&#34;时使用的方法。
答案 3 :(得分:-1)
我通常处理这样的事情的方法是编写一个可以“读入”数据并将其存储到某个结构的函数。然后是一个将数据从结构写入文件的函数。
这样您就可以操纵数组中的数据。这也使得您的程序更易于进行排序或额外数学操作,只需在文件顶部写入即可完成。
e.g。尝试编写一个可以读入结构的函数,如:
struct Client
{
char name[255];
double owes;
double paid;
}
然后你做了一些这些结构的数组并操纵它们。 你将学到很多关于结构,动态内存分配的知识,毫无疑问你会遇到一些有助于你学习的有趣问题。
我的建议是跳过C并转向C ++ ...从长远来看,使用iostream而不是* printf / * scanf函数和向量学习这些东西对你来说可能会更好