c - 使用 fgets 从 .txt 文件读取并打印多行

标签 c arrays file char fgets

FILE *fp = fopen("story.txt", "r");
if(fp == NULL){
    printf("\nError opening file.\nExiting program.\n");
    exit(1);
}
char text[100];

while(fgets(text, 100, fp) != NULL){
    printf("%s", text);
}
printf("\n");
fclose(fp);

我正在尝试打印文本文件的前 100 个字符,包括新行,但是当我使用上面的代码时,它会出现一些奇怪的行为。首先,它仅打印文本文件的最后一行,该行本身不足 100 个字符。另外,如果我在 while 循环中包含两个打印语句,即

while(fgets(text, 100, fp) != NULL){
   printf("%s", text);
   printf("%s", text);

}

它打印文本文件中超过 125 个字符的内容(数千个字符,这是一个很大的文本文件),并且所述文本的内容是来自文件的一堆看似随机的片段,位于一个恒定的流中,不新行或其他任何内容。

所以我想我的问题是有没有办法使用 fgets 以便它从顶部开始打印文件中的文本并包含新行?我最终必须使用它来将文本文件转换为字符数组,以便我可以基于该数组创建一个新的、修改后的字符数组,该数组将被打印到一个新的文本文件中。因此,如果有更好的方法来实现最终目标,我们将不胜感激。

编辑:经过评论中的一些讨论,我意识到我正在使用的文本只是一大块带有回车符且没有换行符的文本。我想此时我的主要问题是如何将这个带有回车符的文本文件转换为字符数组。

最佳答案

如果目标是读取 100 个字符行的文本文件,并去掉回车符,您仍然可以使用 fgets(),只要您记住 fgets() 将读取直到下一个换行符(包括下一个换行符)的字符,或者直到读取到的字符数少于指定的字符数。

下面的代码读取一行文本,最多 BUFFER_SZ-1 个字符,增加内存分配以保存新的文本行,并将该行复制到分配的空间中,删除回车符以及任何尾随的换行符。请注意,重新分配的空间的地址首先存储在临时指针中。 realloc() 在发生分配错误时返回空指针,此步骤避免了潜在的内存泄漏。

由于行在 BUFFER_SZ-1 个字符处断开,因此单词可能会跨行拆分,您可能需要开发额外的逻辑来处理此问题。以更大的 block 和更低的频率重新分配会更有效,而不是像这里所做的那样为每一行分配一次。另请注意,以二进制模式打开文件可能有助于更仔细地解析行结尾。

#include <stdio.h>
#include <stdlib.h>

#define BUFFER_SZ 100

int main(void)
{
    FILE *fp = fopen("story.txt", "r");
    if (fp == NULL) {
        fprintf(stderr, "Unable to open file\n");
        exit(EXIT_FAILURE);
    }

    char buffer[BUFFER_SZ];
    char (*text)[sizeof buffer] = NULL;
    char (*temp)[sizeof buffer] = NULL;
    size_t numlines = 0;

    while (fgets(buffer, sizeof buffer, fp) != NULL) {
        ++numlines;
        /* Allocate space for next line */
        temp = realloc(text, sizeof(*text) * numlines);
        if (temp == NULL) {
            fprintf(stderr, "Error in realloc()\n");
            exit(EXIT_FAILURE);
        }
        text = temp;

        /* Copy buffer to text, removing carriage returns and newlines */
        char *c = buffer;
        char *line = text[numlines-1];
        while (*c != '\n' && *c != '\0') {
            if (*c != '\r') {
                *line++ = *c;
            }
            ++c;
        }
        *c = '\0';
    }

    if (fclose(fp) != 0) {
        fprintf(stderr, "Unable to close file\n");
    }

    for (size_t i = 0; i < numlines; i++) {
        printf("%s\n", text[i]);
    }

    free(text);

    return 0;
}

另一种选择是用换行符替换回车符。这可能就是OP的想法。可以轻松修改上述程序来实现此目的。请注意,\n 已从显示结果的 printf() 语句中删除,因为换行符现在包含在字符串中。

...

    /* Copy buffer to text, converting carriage returns to newlines */
    char *c = buffer;
    char *line = text[numlines-1];
    while (*c != '\n' && *c != '\0') {
        if (*c == '\r') {
            *line++ = '\n';
        } else {
            *line++ = *c;
        }
        ++c;
    }
    *c = '\0';
}

if (fclose(fp) != 0) {
    fprintf(stderr, "Unable to close file\n");
}

for (size_t i = 0; i < numlines; i++) {
    printf("%s", text[i]);
}

...

关于c - 使用 fgets 从 .txt 文件读取并打印多行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43197469/

相关文章:

php - 如何使用css3 UL LI循环并生成分层图表

c - 使用 while 循环发出 fgetc() c

java - 将一个文件的内容重复写入另一个文件并进行特定替换

c - ELF32 静态链接 (PPC 32 ABI)

填充数组的代码突然改变变量(C)

c - 如何计算C中相同字符的个数?

arrays - 从配置文件创建Powershell菜单

c++ - 如何格式化字符串流的输出?

c - 为什么 Microsoft C 库函数 strrev 会修改输入字符串?

标量类型的复合文字