如何在 C 编程中使用 fgets 编写返回文本文件所有内容的函数?

Posted

技术标签:

【中文标题】如何在 C 编程中使用 fgets 编写返回文本文件所有内容的函数?【英文标题】:How can I write a function That returns all the content of a text file using fgets in C programming? 【发布时间】:2022-01-14 06:50:41 【问题描述】:

我想编写一个函数 char* lire(FILE* f),它应该读取文本文件并返回其内容,我想返回它而不仅仅是读取它并显示它。 我想使用 fgets。

此代码有效,但不是我想要的

 char *lire(FILE *f)

    char *content;
    content = (char*)malloc((strlen(content) + 1) * sizeof(char));
    
   while (fgets(content,120000, f) )
   
      printf("%s", content);
   
   return 0;

相反,我尝试了返回文本文件,但它只显示了我的文本文件的第一行

char *lire(FILE *f)

    char *content;
    content = (char*)malloc((strlen(content) + 1) * sizeof(char));
    
   while (fgets(content,120000, f) )
   
     return content;
   
   

【问题讨论】:

fgets 只读取一行文本。除非文件包含一行文本,否则无法使用 fgets 读取整个文件。你可能需要fread 顺便说一句:当content 是一个未初始化的指针时,你认为strlen(content) 是什么? 我不明白为什么可以使用它来读取第一个代码中的多行,而第二个代码中却没有。谢谢。 这两个代码 sn-ps 都存在多个问题。先处理我的第二条评论。这很重要,相信我。 在您的第一个代码中,您打印该行,然后在循环中进行另一轮。这种情况接二连三地发生。 fgets 不超过那一行。在第二个代码中,您只是退出工作并在第一行之后返回。 【参考方案1】:

有几种方法可以使用fgets() 将整个文本文件读入单个字符串,但它们都将迭代使用fgets()。您可以尝试预先确定文件的大小,然后分配足够的空间并读入该空间。这适用于您可以在文件中查找的磁盘文件;如果输入来自管道、终端、套接字或大多数其他不是磁盘文件的东西,它就不起作用。还有一个TOCTOU(检查时间,使用时间)问题;当您的代码读取文件时,文件大小可能会发生变化。

或者,您可以简单地读入分配的空间,在需要时重新分配更多空间。这适用于任何类型的输入文件。

使用fgets() 意味着文件不能有效地包含空字节。那是因为fgets() 没有报告它读取了多少数据,所以你必须使用strlen() 来找出数据的长度,而strlen() 在它遇到的第一个空字节处停止。

使用增量分配,您可能会得到如下代码:

/* SO 7028-9928 */
/* Slurp a file using fgets() */

/* #include "slurp.h" */
/* SOF - slurp.h */
#include <stdio.h>

extern char *slurp_file(FILE *fp);
/* EOF - slurp.h */

#include <stdlib.h>
#include <string.h>

#define INIT_ALLOC 1024
#define MIN_SPACE   256
#define MAX_EXCESS  256

char *slurp_file(FILE *fp)

    size_t offset = 0;
    size_t bufsiz  = INIT_ALLOC;
    char *buffer = malloc(bufsiz);
    if (buffer == NULL)
        return NULL;
    while (fgets(buffer + offset, bufsiz - offset, fp) != NULL)
    
        /* Assumes data does not contain null bytes */
        /* Generic problem using fgets() */
        size_t newlen = strlen(buffer + offset);
        offset += newlen;
        if (bufsiz - offset < MIN_SPACE)
        
            size_t new_size = bufsiz * 2;
            char  *new_data = realloc(buffer, new_size);
            if (new_data == NULL)
            
                free(buffer);
                return NULL;
            
            bufsiz = new_size;
            buffer = new_data;
        
    
    if (bufsiz - offset > MAX_EXCESS)
        buffer = realloc(buffer, offset + 1);
    return buffer;


int main(void)

    char *data;
    if ((data = slurp_file(stdin)) != NULL)
    
        printf("Size: %zu\n", strlen(data));
        printf("Data: [[%s]]\n", data);
        free(data);
    
    return 0;

当程序在自己的源代码上运行时,它会产生如下输出:

Size: 1362
Data: [[/* SO 7028-9928 */
/* Slurp a file using fgets() */

…
    return 0;

]]

另一种方法是使用fread() 而不是fgets() — 这可以处理二进制数据,但您需要修改函数接口以报告数据的长度和指向数据开头的指针。

【讨论】:

以上是关于如何在 C 编程中使用 fgets 编写返回文本文件所有内容的函数?的主要内容,如果未能解决你的问题,请参考以下文章

C 语言文件操作 ( 按照文本行的方式读写文件 | fgets 函数 | fputs 函数 )

C 编程 - 调用 fgets() 两次?

如何用浏览器打开用记事本编写的代码

试图理解 fgets()

c语言编程:编写程序,实现文本文件的复制。从一个文件中逐个字符输出,将其中的小写字母转换成大写字母

在 C 中使用 fgets 时出现“分段错误:11”