在C语言的标准库里,有读取一行文件内容的函数fgets,头文件是stdio.h。
今天弄了个乌龙,在Windows下编辑的文件,放到Linux里面去读,用fgets读取一行内容,然后进行处理。
读取内容是一个字符串,表示需要操作的串口,比如"/dev/ttyS1",结果因为Windows和Linux行结束符不同,导致操作串口失败。
这个问题导致硬件验证不通过,挖了个大坑,别人用其他板子试验的结果OK,我试验就不OK,发现就是配置文件生成方式不同,其他硬件信号测量也正确,操作方式也一样。
然后把文件的行结束格式改了一下,就好了。
所以个把这个函数拎出来,做个记录。
说明
C库函数char *fgets(char *str, int n, FILE *stream)从指定的流中读取一行,并将其存入str所指向的字符串中。当读到(n-1)个字符、读到换行符或到达文件末尾时(以先到者为准),它就停止。
函数声明
char *fgets(char *str, int n, FILE *stream)
参数
str - 读取的字符串,将存储在str所指向的字符数组。
n - 可以读取的最大字符的数量,包括最后的字符串结束符(null-character)。一般使用str参数所传递的数组的长度。
stream - 指向一个FILE对象的指针,标识着读取字符串的流。
返回值
如果执行成功,函数返回str参数同样的值。如果读取到End-of-File符号,即文件结束符,并且没有读取到任何字符,则str的值保持不变,但返回的是一个空指针。
如果执行错误,则返回一个空指针。
示例
Linux下运行:
#include <stdio.h>
#include <string.h>
int main() {
FILE *fp;
char str[60];
/* opening file for reading */
fp = fopen("file.txt", "r");
if(fp == NULL) {
perror("Error opening file");
return (-1);
}
for(int i = 0; i<10; i++) {
if(fgets(str, 60, fp) != NULL) {
/* writing content to stdout */
puts(str);
printf("len is %ld.\n", strlen(str));
}
}
fclose(fp);
return (0);
}
$ gcc -o test fgets.c
$ ./test
然后当当前文件夹下编辑一个file.txt,进行测试。
$ cat file.txt
1234
$ hexdump -c file.txt
0000000 1 2 3 4 \r \n
0000006
$ hexdump -C file.txt
00000000 31 32 33 34 0d 0a |1234..|
00000006
$ ./test
1234
len is 6.
$
测试结果证明:
1,fgets是一行行读取内容,并返回包含内容的指针,Linux下根据'\n'字符(换行符)来分隔每一行,返回的内容里包含换行符。
2,读取内容后,会在结尾加上字符串结束符null字符,也就是'\0'。
3,最后一次读取会读取到文件结束符,返回的指针是文件结束符之前的最后一行内容,但不一定是以换行符结尾。
4,读取到文件结束符之后,再读取,就返回NULL指针了。
5,如果文件本身大小为0,使用fgets第一次读取文件就会返回NULL指针。
6,如果是Windows结果格式文件,(CR LF, 0x0D 0x0A),那读取一行的内容,那结尾就会多出这两个字符。如果是Unix格式,就是有一个LF换行符,0x0A。
所以读取内容后使用时,要注意最后面会有CR,LF等字符,如果处理不当,就会和我上面一样,自己给自己挖坑。
另外,我只在Linux下进行了测试,没有使用Windows平台下的C语言开发工具,但对C语言来讲,fgets是标准库函数,行为都是一样的。
参考: