为什么fputc不更新此代码段中的字符?

时间:2017-07-14 09:53:38

标签: c file file-handling

#include <stdio.h>

int main() {
    FILE *fp;
    char ch = 'g';
    fp = fopen("temp.txt", "r+"); 
    while (feof(fp)) {
        fputc(ch,fp);
        fseek(fp, 1, SEEK_CUR);
   }
   fclose(fp);
}

根据这个问题,我希望代码将所有字符更新为'g'。但是我发现它什么也没做。

2 个答案:

答案 0 :(得分:1)

因此,您希望将文件中的所有字节更改为字母g。可移植且可靠地在文本流上执行此操作非常困难 1 。我建议您以二进制模式打开流,并执行以下操作:

#include <errno.h>
#include <stdio.h>
#include <string.h>

int main(void) {
    char buf[4096];
    long len;
    FILE *fp;

    fp = fopen("temp.txt", "rb+"); 
    if (fp == NULL) {
        fprintf(stderr, "cannot open temp.txt: %s\n", strerror(errno));
        return 1;
    }
    while ((len = fread(buf, 1, sizeof buf, fp)) > 0) {
        fseek(fp, -len, SEEK_CUR);
        memset(buf, 'g', len);
        fwrite(buf, 1, len, fp);
        fseek(fp, 0, SEEK_CUR);
    }
    fclose(fp);
    return 0;
}

您的问题并不完全清楚:如果通过将所有字符更新为'g',您的意思是保留不是字符的未更改字节,例如换行标记,代码将更多一些微妙。编写一个读取流并生成带有更改的输出流的过滤器要简单得多:

例如,这是一个将所有字母都更改为g的过滤器:

#include <ctype.h>
#include <stdio.h>

int main(void) {
    int c;

    while ((c = getchar()) != EOF) {
        if (isalpha(c))
            c = 'g';
        putchar(c);
    }
    return 0;
}
  1. 无法在文本模式下使用ftell()来计算文件中的字符数。您必须使用二进制模式:
  2.   

    C 7.21.9.4 ftell函数

         

    <强>概要

    #include <stdio.h>
      long int ftell(FILE *stream);
    
         

    <强>描述

         

    ftell函数获取stream指向的流的文件位置指示符的当前值。对于二进制流,该值是文件开头的字符数。对于文本流,其文件位置指示符包含未指定的信息,fseek函数可使用该信息将流的文件位置指示符返回到ftell调用时的位置;两个这样的返回值之间的差异不一定是写入或读取的字符数的有意义的度量。

         

    <强>返回

         

    如果成功,ftell函数将返回流的文件位置指示符的当前值。失败时,ftell函数返回−1L并在errno中存储实现定义的正值。

    即使计算用getc()读取的字符并从文件开头写入相同数量的'g' s也不起作用:换行序列可能使用多个字节和一些文件内容最终可能不会在某些遗留系统上被覆盖。

答案 1 :(得分:1)

  

成功调用fseek()函数会清除文件结尾   流的指标

提到了here。并且还将文件写入文件扩展其大小。所以首先我们需要确保我们不会超出文件的大小。作为@chqril的回答,他通过读取文件确定边界,然后用更改的数据写入相同的部分。

这是我的解决方案,我首先找到文件的大小,然后从头到尾编写它。它仅在文件中的每个字符只占用一个字节时才有效。

#include <stdio.h>

int main()
{
    unsigned char ch = 'g';
    FILE* fp = fopen("tmp.txt","rb+");

    if (fp == NULL)
    {
        printf("cannot open file\n");
        return -1;
    }

    //seek to last byte
    if (fseek(fp, 0, SEEK_END) != 0)
    {
        printf("error during seeking\n");
        fclose(fp);
        return -1;
    }

    /*get current offset relative to start.
     *this is file size in bytes
     */
    long size = ftell(fp);

    if (size < 0)
    {
        printf("error during ftell");
        fclose(fp);
        return -1;
    }

    //reset pointer to start of file
    rewind(fp);

    /*overwrite every byte
     *this only works if file
     *size is static
     */
    for (long i = 0; i < size; ++i)
    {
        fputc(ch, fp);
    }

    fclose(fp);

    return 0;
}