Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C-从文件中删除/修改行_C_File Io - Fatal编程技术网

C-从文件中删除/修改行

C-从文件中删除/修改行,c,file-io,C,File Io,我有一个datas.txt文件: 格式:姓名债务支付 bir bir 100 2 iki iki 200 2 eray alakese 100 5 john doe 2000 10 我正在学习C,我只知道简单的文件函数(fscanf、fprinf、fopen等) 我会 使用scanf询问用户名和姓氏,然后将其分配给名称和姓氏变量 它将搜索文件的名称和姓氏,然后将债务和付款分配给债务、付款变量(fscanf(文件,“%s%s%d%d”、名称、姓氏、债务和付款);) 删除或修改此行 这是我

我有一个datas.txt文件:

格式:姓名债务支付

bir bir 100 2 
iki iki 200 2 
eray alakese 100 5 
john doe 2000 10 
我正在学习C,我只知道简单的文件函数(fscanf、fprinf、fopen等)

我会

  • 使用
    scanf
    询问用户名和姓氏,然后将其分配给名称和姓氏变量
  • 它将搜索文件的名称和姓氏,然后将债务和付款分配给债务、付款变量(
    fscanf(文件,“%s%s%d%d”、名称、姓氏、债务和付款);
  • 删除或修改此行
  • 这是我的源代码

        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);
    
    示例:

  • 我想删除“John Doe”的记录
  • 我想把“约翰·多伊”的债务减少到100英镑$

  • 不能删除/修改文本文件的[*]行;唯一的解决方案是1)创建新的临时文件,2)将内容复制到(但不包括)要修改/删除的行,3)输出修改的行,4)复制原始文件的其余部分,5)用临时文件替换旧文件

    [*]仅当修改的行与原始行具有相同的长度时,才可以进行修改


    编辑:PS:使用fgets,然后使用sscanf(或其他标记行的方式)将为您省去很多痛苦。

    您不能删除/修改文本文件的[*]行;唯一的解决方案是1)创建新的临时文件,2)将内容复制到(但不包括)要修改/删除的行,3)输出修改的行,4)复制原始文件的其余部分,5)用临时文件替换旧文件

    [*]仅当修改的行与原始行具有相同的长度时,才可以进行修改


    编辑:PS:使用fgets,然后使用sscanf(或其他标记行的方式)将为您省去很多痛苦。

    通常要做的事情是读取所有文件并将其全部写回临时文件,然后删除原始文件并重命名临时文件

    /* pseudo-code!! */
    fopen();
    while (fscanf(source, ...)) {
        /* massage data */
        fprintf(temporary, ...);
    }
    fclose();
    remove(source);
    rename(temporary, source);
    

    通常要做的事情是读取所有文件并将其写回临时文件,然后删除原始文件并重命名临时文件

    /* pseudo-code!! */
    fopen();
    while (fscanf(source, ...)) {
        /* massage data */
        fprintf(temporary, ...);
    }
    fclose();
    remove(source);
    rename(temporary, source);
    

    为了删除或更改一行,您必须“移动”它后面的所有内容。例如,考虑这两个文件:

    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字节0-14
    iki iki 200 2字节15-29
    
    john doe 2000 10字节30-57为了删除或更改一行,您必须“移动”后面的所有内容。例如,考虑这两个文件:

    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字节0-14
    iki iki 200 2字节15-29
    
    john doe 2000 10 bytes 30-57这有点难,因为C的文件模型继承自Unix(它们大部分是共同开发的),实际上并没有将文件定义为行列表。相反,它将一行定义为以换行符结尾的字节字符串,将一个文件(大致)定义为一个存储的长度可能有限的字节字符串,您可以在其中跳到不同的部分。这相当含糊,但请容忍我

    当我们试图将我们的想法——“修改这一行”、“删除那一行”转化为文件操作时,问题变得更清楚了。我们只需停在换行符上就可以读取一行,但根本没有命令将其切分为多个部分;仅设置结束(ftruncate())。所以要改变行的大小,我们需要复制它后面的所有数据。这是可以做到的,但是重新创建文件通常更容易。比较实现memmove()的微妙之处

    传统的方法有两种,这取决于你能容忍的副作用

    一种是将更新后的版本写入另一个文件,然后将其重命名()。这样做的好处是,新文件将在您放置到位时完成,但缺点是,在权限等方面,它可能与旧文件不完全匹配,并且其他已打开旧文件的程序将看不到它。如果两个程序像这样修改文件,这是一个竞争条件,因为其中一个更改被另一个更改覆盖

    另一种方法是完全加载数据,并将修改后的版本写在适当的位置。这意味着文件本身、权限和所有内容都保持不变,但在保存时会有一段时间,即它是新旧内容的混合体。文本编辑器倾向于这样做,通常同时将旧内容保存为单独的文件,以防出错


    还有一些工具可以管理这些副作用,例如版本化的文件系统、文件锁定,甚至还有为并行更改准备的库(我想到的是metakit)。大多数时候,我们将使用已经存在的工具,比如sed-i

    这有点难,因为C的文件模型继承自Unix(它们大部分是共同开发的),实际上并没有将文件定义为行列表。相反,它将一行定义为以换行符结尾的字节字符串,将一个文件(大致)定义为一个存储的长度可能有限的字节字符串,您可以在其中跳到不同的部分。这相当含糊,但请容忍我

    当我们试图将我们的想法——“修改这一行”、“删除那一行”转化为文件操作时,问题变得更清楚了。我们只需停在换行符上就可以读取一行,但根本没有命令将其切分为多个部分;仅设置结束(ftruncate())。所以要改变行的大小,我们需要复制它后面的所有数据。这是可以做到的,但是重新创建文件通常更容易。比较实现memmove()的微妙之处

    传统的方法有两种,这取决于你能容忍的副作用

    一种是将更新后的版本写入另一个文件,然后将其重命名()。这样做的好处是,新文件将在您放置到位时完成,但缺点是它可能与旧文件不匹配