1

我是 C 的新手,正在尝试学习如何读取文件。我的文件是一个简单的文件(仅用于测试),其中包含以下内容:

this file
has been
successfully read
by C!

所以我使用以下 C 代码读取文件:

#include <stdio.h>

int main() {

   char str[100];
   FILE *file = fopen("/myFile/path/test.txt", "r");

   if(file == NULL) {
      puts("This file does not exist!");
      return -1;
   }

   while(fgets(str, 100, file) != '\0') {
      puts(str);
   }

   fclose(file);

   return 0;
}

这会像这样打印我的文本:

this file

has been

successfully read

by C!

当我编译并运行它时,我将它的输出通过管道传输到并且可以在每行的末尾hexdump -C看到一个额外的内容。0a

最后,为什么我需要声明一个字符数组来从文件中读取?如果我不知道每行有多少数据怎么办?

4

2 回答 2

8

fgets()读取换行符并将换行符保留在字符串中,并puts()始终在要打印的字符串中添加换行符。因此,当在代码中使用时,您会得到双倍行距的输出。

使用fputs(str, stdout)代替puts(); 它不添加换行符。

过时的函数gets()——从 2011 版本的 C 标准中删除——读取到换行符但删除了它。gets()puts()对一起工作得很好, 和也是fgets()如此fputs()。但是,您当然应该使用gets(); 这是一场等待发生的灾难。(1988 年第一个互联网蠕虫曾经gets()迁移——谷歌搜索“莫里斯互联网蠕虫”)。


在评论中,调查官问道:

为什么需要将行读入特定大小的 char 数组?

因为您需要确保不会超出可用空间。C 不会为字符串自动分配空间。从某些角度来看,这是它的弱点之一。它也是一种优势,但它经常使语言新手感到困惑。如果您希望输入代码为一行分配足够的空间,请使用 POSIX 函数getline()

那么在我点击 a 之前读取和输出是否更好,'\0'因为我并不总是知道给定行上的字符数量?

不。一般来说,你不会打'\0';大多数文本文件不包含任何这些。如果您不想为一行分配足够的空间,请使用:

int c;
while ((c = getchar()) != EOF)
    putchar(c);

它在用户代码中一次读取一个字符,但底层标准 I/O 包会缓冲输入,因此成本不会太高——以这种方式实现程序是完全可行的。如果您需要处理线条,请为线条分配足够的空间(我char buffer[4096];经常使用)或使用getline().

查理伯恩斯在评论中问道:

为什么我们不经常看到建议使用 getline()?

我认为它并没有经常被提及,因为getline()它相对较新,而且不一定在任何地方都可用。它被添加到 POSIX 2008;它在 Linux 和 BSD 上可用。我不确定其他主流 Unix 变体(AIX、HP-UX、Solaris)。为自己编写并不难(我已经完成了),但是如果您需要编写可移植的代码(特别是如果“可移植”包括“微软”),那就很麻烦了。它的优点之一是它告诉你它实际读取的行有多长。

使用示例getline()

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

int main(int argc, char **argv)
{
    char *line = 0;
    size_t length = 0;
    char const name[] = "/myFile/path/test.txt";
    FILE *file = fopen(name, "r");

    if (file == NULL)
    {
        fprintf(stderr, "%s: failed to open file %s\n", argv[0], name);
        return -1;
    }

    while (getline(&line, &length, file) > 0) 
        fputs(str, stdout);

    free(line);
    fclose(file);

    return 0;
}
于 2013-11-07T16:44:57.777 回答
5

fgets逐行读取时将换行符保存在行尾。这使您可以确定是否实际读取了一行或只是您的缓冲区太小。

puts打印时总是添加换行符。

修剪换行符fgets或使用printf

printf("%s", str);
于 2013-11-07T16:45:08.637 回答