【问题标题】:How do I read a text file and store its content into another string? C如何读取文本文件并将其内容存储到另一个字符串中? C
【发布时间】:2020-03-18 02:23:55
【问题描述】:

我想将“file.txt”的内容复制到字符串“buf”中。当我运行程序时,它似乎只打印出“我爱蛋糕”的字样。

file.txt 的内容在这一行下面

你好,你好吗

你喜欢蛋糕吗

我喜欢蛋糕

//Variable Declarations
char buf[256] = "";
char dest[256] = "";


//Check if the file exists
FILE* fp;
fopen_s(&fp ,"file.txt", "r");
if (fp != NULL) {
    printf("File has been opened\n");
}
else
{
    printf("File did not open\n");
}

while (!feof(fp)) 
{
    fgets(buf, 256, fp);
}


printf("%s\n", buf);

【问题讨论】:

  • feof 这样的状态报告功能只会告诉您过去已经发生的事情。您不能使用它们来预测未来——在这种情况下,无论对尚未发生的 fgets 的调用是否会遇到文件结尾。

标签: c string file


【解决方案1】:

阅读while (!feof(fp)) is always wrong

由于要一次读取整个文件,最好使用fread,以读取模式(非二进制)打开文件:

FILE *fp = . . .;

fseek(fp, 0, SEEK_END);
long n = ftell(fp);
rewind(fp);

char *buf = malloc(n+1);
fread(fp, buf, 1, n);
buf[n] = 0;

fclose(fp);

省略错误处理。

【讨论】:

    【解决方案2】:

    当您想读取行并将其追加到固定缓冲区时,您需要跟踪缓冲区中的位置以追加新字符,然后每次添加后可用的字符数。当您从输入流中读取行时,您不会以while (!feof (file)) 为条件读取循环。 (见:Why is while ( !feof (file) ) always wrong?

    相反,您可以根据正在使用的输入函数的返回来调节读取循环,或者不断循环,检查输入函数的返回当你的输入函数返回EOF(或者你没有处理的读取错误发生)时你打破循环

    对于 256 字符缓冲区的情况,您可以简单地声明 256 字符数组进行存储,然后声明一个指向数组开头的指针,您将使用该指针在缓冲区中写入新字符,推进指针把那些写完,为下一次阅读做准备。读取要添加的字符时,您最多只能读取缓冲区中未使用的可用字符数。无论您是使用strcpy/strcat 还是只是在指针位置将字符读入缓冲区都无关紧要——跟踪剩余的可用字符是相同的。

    在计算剩余可用字符数时唯一需要注意的是,您必须为 nul-terminating 字符保留存储空间。您只需要一个用于在缓冲区中构建的字符串,因此它会与您添加到缓冲区的第一个字符串一起添加。

    连接字符串时,您还需要考虑如何处理输入文件中的空白(空)行。由于它们不会添加到您要加入的字符串中,您可以直接跳到下一行 - 除非您想将它们保留在缓冲区中。

    当使用fgets() 或POSIX getline() 等面向行的读取函数时,您还必须处理'\n' 读取并包含在每次读取中。在连接字符串时处理包含的'\n' 的简单方法是用' '(空格)字符覆盖它,以便在缓冲区中的相邻字符串之间提供一个空格。

    最后要考虑的是在退出读取循环时从缓冲区末尾删除最后的' '(空格)。 (用' ' 覆盖'\n' 产生的结果)。只需递减您正在使用的指针,并用 nul-terminating 字符覆盖最后的 ' '

    总而言之,你可以做类似的事情:

    #include <stdio.h>
    #include <string.h>
    
    #define MAXC 256    /* if you need a constant, #define one (or more) */
    
    int main (void) {
    
        char buf[MAXC], *p = buf;   /* buffer and pointer to buffer  */
        size_t avail = MAXC;        /* character avaialble in buffer */
    
        while (fgets (p, avail, stdin)) {   /* read up to avail characters */
            size_t len = strlen(p);         /* get length read */
            if (*p == '\n')                 /* ignore blank lines in input */
                continue;
            if (len && p[len-1] == '\n')    /* overwrite \n with space */
                p[len-1] = ' ';
            p += len;                       /* advance len chars in buf */
            /* subtract len chars from avail (len + 1 chars 1st iteration) */
            avail -= (avail == MAXC) ? len + 1 : len;
        }
        if (*--p == ' ')    /* backup over space at end and nul-terminate */
            *p = 0;
    
        puts (buf);     /* output combined string */
    }
    

    注意:处理前导空格、多个中间空格或尾随空格留给您)

    输入文件示例

    $ cat dat/cake.txt
    Hi there how are you
    do you like cake
    I love cake
    

    或有空行的文件:

    $ cat dat/cakedbl.txt
    Hi there how are you
    
    do you like cake
    
    I love cake
    

    使用/输出示例

    附加文件中的所有行,由空格分隔,最多为 MAXC - 1 个字符(为 nul-termianting 字符留出空间)。

    $ ./bin/appendstr < dat/cake.txt
    Hi there how are you do you like cake I love cake
    

    双倍行距文件。

    $ ./bin/appendstr < dat/cakedbl.txt
    Hi there how are you do you like cake I love cake
    

    查看一下,如果您还有其他问题,请告诉我。使用strcpystrcat 重写程序以连接字符串。 (您会发现使用单个缓冲区时它基本上是一种洗涤)。您可以使用 strcpy/strcat 方法使用单独的缓冲区进行读取和追加以简化操作,但剩余可用字符的计算基本相同。

    【讨论】:

      【解决方案3】:

      fgets 会将旧缓冲区替换为新缓冲区,您必须将下一个缓冲区放在缓冲区指针的下一个偏移量中。

      #include <stdio.h>
      #include <string.h>
      
      int main()
      {
          //Variable Declarations
          char buf[256] = "";
          char dest[256] = "";
          char *ptr = buf;
      
      
          //Check if the file exists
          FILE* fp;
          fp = fopen("file.txt", "r");
          if (fp != NULL) {
              printf("File has been opened\n");
          }
          else
          {
              printf("File did not open\n");
          }
      
          while (!feof(fp)) 
          {
              fgets(ptr, 256, fp);
              ptr += strlen(ptr);
          }
      
      
          printf("%s\n", buf);
      }
      

      【讨论】:

      • ptr += strlen(ptr); 使fgets(ptr, 256, fp); 中的256 毫无意义。
      • @DavidRankin-ReinstateMonica 不,fget 不保证渲染 256 字节,它只会渲染到换行符 \n。但是,如果文件大小超过 256 字节,则可能会发生溢出。
      • 重点是在您将ptr 推进到buf 之后,就不再有256 剩余的字符了。因此,您需要在下次调用 fgets() 之前从 256 中减去使用的字符数。
      【解决方案4】:

      fgets 在读取换行符或 EOF 后停止。所以你要重新写入同一个缓冲区。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多