使用fgets从.txt文件

时间:2017-04-04 02:54:15

标签: 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循环中包含两个print语句,即

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

}

它打印了超过125个文本文件的字符(数千个地方,它是一个大文本文件),并且所述文本的内容是一个看似随机的段,来自文件中的一个常量流,没有新线或任何东西。

所以我想我的问题是有没有办法使用fgets,以便从顶部开始打印文件中的文本,并包含新行?我最终必须使用它将文本文件转换为字符数组,以便我可以根据该数组创建一个新的,修改过的字符数组,该数组将打印到新的文本文件中。因此,如果有更好的方法来实现最终目标,那将是值得赞赏的。

编辑:在评论中进行了一些讨论之后,我意识到我使用的文本只是一个大块的文本,带有回车而没有新行。我想在这一点上我的主要问题是如何将带有回车的文本文件转换为字符数组。

2 个答案:

答案 0 :(得分:0)

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

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

由于行以BUFFER_SZ-1个字符被破坏,因此单词可能会跨行分割,您可能需要开发其他逻辑来处理此问题。如此处所做的那样,以更大的块更频繁地重新分配更有效,而不是每行重新分配一次。另请注意,以二进制模式打开文件以更仔细地解析行结尾可能很有用。

#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]);
}

...

答案 1 :(得分:0)

它不会将一行复制到另一行的末尾。它只是重用您不断传递的缓冲区。如果要存储多行,请将其复制到另一个缓冲区,然后将它们连接起来。 (请参阅:strcat)