我是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
。
最后,为什么我需要声明一个chars数组来从文件中读取?如果我不知道每行有多少数据怎么办?
答案 0 :(得分:8)
fgets()
读取换行符并将换行符保留在字符串中,puts()
始终为要打印的字符串添加换行符。因此,当您在代码中使用时,您将获得双倍行距输出。
使用fputs(str, stdout)
代替puts()
;它不会添加换行符。
过时的函数gets()
- 从2011版的C标准中删除 - 读取到换行符但删除了它。 gets()
和puts()
对合作得很好,fgets()
和fputs()
也是如此。但是,你当然应该 NOT 使用gets()
;这是一场等待发生的灾难。 (1988年第一个互联网蠕虫使用gets()
进行迁移 - 谷歌搜索'莫里斯互联网蠕虫')。
在评论中,inquisitor问道:
为什么需要将行读入特定大小的char数组?
因为您需要确保不会超出可用空间。 C不会为字符串自动分配空间。从某些观点来看,这是它的弱点之一;它也是一种力量,但它通常会使新手与语言混淆。如果您希望输入代码为行分配足够的空间,请使用POSIX函数getline()
。
因为我不会总是知道给定行上的字符数量,所以最好只读取并输出直到
'\0'
为止?
没有。一般来说,你不会点击'\0'
;大多数文本文件不包含任何这些文件。如果您不想为一行分配足够的空间,请使用:
int c;
while ((c = getchar()) != EOF)
putchar(c);
在用户代码中一次读取一个字符,但底层标准I / O包缓冲输入,因此不会太昂贵 - 以这种方式实现程序是完全可行的。如果你需要在线上工作,要为线分配足够的空间(我经常使用char buffer[4096];
)或使用getline()
。
Charlie Burns在评论中提到:
为什么我们不经常看到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;
}
答案 1 :(得分:5)
fgets
在逐行阅读时将换行符保存在行尾。这样可以确定实际读取了一行,或者只是缓冲区太小了。
puts
始终在打印时添加换行符。
从fgets
修剪换行符或使用printf
printf("%s", str);