该系列为本人的学习笔记,主要由本人整理书写而成。部分内容来自教材、视频课程等,不能保证完全原创性。
萌新的学习笔记,写错了恳请斧正。
# 光标 (文件位置指示器)
我们平常打字的时候就知道光标这个概念,而程序在打开文件后也是有一个光标,用于控制文件的读写。我们一般说文件指针指向文件的哪个位置,其实就是光标 (文件位置指示器) 指向文件的某个位置,而这个信息也是保存在对应流的结构体中的。
读和写操作都是从光标的位置进行,而光标的位置也随着读写移动
# 文件的顺序读写
文件的顺序读写就是从光标的位置开始,按顺序向后读写内容
文件顺序读写时我们没法随意控制光标的位置,只能让系统自己控制光标
# fgetc
#include <stdio.h> | |
int fgetc( FILE* stream ); |
fgetc 是字符输入函数,从指定的输入流读取下一个字符,并返回这个字符
如果读取失败则返回 EOF, 但是遇到文件尾导致的读取失败会设置流结构体上的文件尾指示器 (这是有用的,后面 feof 函数会讲), 而其他错误导致的失败会设置流结构体上的错误指示器 (这在 ferror 函数中用得到)
其实 getchar 其实就可以理解为 fgetc (stdin), 从标准流读一个字符
但是注意:尽量使 stream 不要是一个带有副作用的表达式 (它被重复计算)
# 使用实例
其中的错误处理部分暂且不表,后面讲
#include <stdio.h> | |
#include <stdlib.h> | |
int main() | |
{ | |
FILE* fp = fopen("test.txt", "r"); | |
if (!fp) | |
{ | |
perror("File opening failed"); | |
return EXIT_FAILURE; | |
} | |
int c; // 注意:int, 非 char, 要求处理 EOF | |
while ((c = fgetc(fp)) != EOF) // 标准 C I/O 读取文件循环 | |
{ | |
putchar(c); | |
} | |
if (ferror(fp)) | |
puts("I/O error when reading"); | |
else if (feof(fp)) | |
puts("End of file reached successfully"); | |
fclose(fp); | |
fp = NULL; | |
return EXIT_SUCCESS; | |
} |
# fputc
#include <stdio.h> | |
int fputc( int ch, FILE* stream ); |
fputc 是字符输出函数,向指定的输入流输出字符,并返回这个字符
如果输出失败则返回 EOF 并设置流结构体上的错误指示器
其实 putchar (ch) 其实就可以理解为 fputc (ch, stdin), 向标准流输出一个字符
但是注意:尽量使 stream 不要是一个带有副作用的表达式 (它被重复计算)
# 使用实例
其中的错误处理部分暂且不表,后面讲
#include <stdio.h> | |
#include <stdlib.h> | |
int main() | |
{ | |
int ret_code = 0; | |
for (char c = 'a'; (ret_code != EOF) && (c <= 'z'); c++) | |
ret_code = putc(c, stdout); | |
/* 测试是否抵达 EOF */ | |
if (ret_code == EOF) | |
if (ferror(stdout)) | |
{ | |
perror("putc()"); | |
fprintf(stderr, "putc() failed in file %s at line # %d\n", __FILE__, __LINE__ - 7); | |
exit(EXIT_FAILURE); | |
} | |
putc('\n', stdout); | |
return EXIT_SUCCESS; | |
} |
# fgets
#include <stdio.h> | |
char* fgets( char* str, int count, FILE* stream ); |
fgets 是文本行输入函数,从指定的输入流读取最多 count-1 个字符并将其存储在 str 所指向的字符数组 (以覆写的形式,不会清除原本内容), 若是遇到文件尾或换行符则提前结束输入。如果是遇到换行符结束,那么 str 的结尾也将包含一个换行符;如果是遇到文件尾结束,那么 str 的结尾没有换行符。只要没有出错,读取的字符串结尾都会补上 '\0'。
- 如果读取成功,则返回值就是 str
- 如果一个字符都没读取就直接遇到文件尾,则判定为失败,返回 NULL 且不会以 '\0' 覆写 str 的首字节,同时设置流结构体的文件尾指示器
- 如果遇到其他错误导致失败,则设置流结构体的错误指示器和 errno, 此时 str 数组会发生什么谁也不知道
count 小于等于 1 的情况是未定义的,不要这么做
# fputs
#include <stdio.h> | |
int fputs( const char* str, FILE* stream ); |
fputs 是文本行输出函数,向指定的输出流 (stream) 输出以 '\0' 结尾的字符串 str 的每一个字符 (空字符不被写入)。如果输出成功,返回一个非负值 (未定义,有些编译器返回写入的字符数,有些返回最后一个字符); 如果输出失败,返回 EOF 并设置流结构体的错误指示器和 errno。
fputs 与 puts 还有一个区别,puts 在输出后会再多输出一个换行符,fputs 不会
# 使用实例
#include <stdio.h> | |
int main() | |
{ | |
int rc = fputs("Hello world!", stdout); | |
if (rc == EOF) | |
perror("fputs()"); | |
return EXIT_SUCCESS; | |
} |
# fscanf
#include <stdio.h> | |
int fscanf( FILE* stream, const char* format, ... ); |
fscanf 相比 scanf 除了可以选择从任意流 stream 输入外就没有什么区别了,都有被读字符串 **(应当以 '\0' 结尾)** 和可变参数列表。返回值为成功接受参数的数量 (可以为 0)。
直接遇到文件尾或读取失败则返回 EOF, 并设置流结构体上相关指示器
# fprintf
#include <stdio.h> | |
fprintf( FILE* stream, const char* format, ... ); |
fprintf 相比 printf 除了可以选择向任意流 stream 输出外就没有什么区别了,都有格式控制字符串和可变参数列表。返回值为输出到流的字符数,如果输出错误或者编码错误则返回一个负值 (未定义)。
# fread
#include <stdio.h> | |
size_t fread( void* buffer, size_t size, size_t count, FILE* stream ); |
fread 是二进制输入函数,从指定流 stream 读取最多 count 个大小为 size 字节的对象到数组 buffer 中。读取成功则返回读取的对象数;读取出现错误或文件尾,返回值是小于 count 的未定义值并设置流结构体上相关指示器; 如果 size 或 count 是零则返回零且不进行其他动作。
官网上描述如下:
如同转译每个对象为 unsigned char 数组,并对每个对象调用 size 次 fputc 以将那些 unsigned char 按顺序写入 stream 一般写入。文件位置指示器前进写入的字节数。
# fwrite
fread 是二进制输出函数,从数组 buffer 向指定流 stream 输出最多 count 个大小为 size 字节的对象。输出成功则返回读取的对象数;输出出现错误,返回值是小于 count 的未定义值; 如果 size 或 count 是零则返回零且不进行其他动作。
官网上描述如下:
如同转译每个对象为 unsigned char 数组,并对每个对象调用 size 次 fputc 以将那些 unsigned char 按顺序写入 stream 一般写入。文件位置指示器前进写入的字节数。
# 使用实例
其中 fseek 函数用于移动光标,后面随机读写会讲
#include <stdio.h> | |
#include <stdlib.h> | |
struct Stu | |
{ | |
char name[20]; | |
int age; | |
float score; | |
}; | |
int main() | |
{ | |
struct Stu s = { "zhangsan", 20, 99.9 }; | |
struct Stu d = { 0 }; | |
FILE* pf = fopen("dat.txt", "w+b"); | |
if (!pf) | |
{ | |
perror("fopen"); | |
return EXIT_FAILURE; | |
} | |
fwrite(&s, sizeof(s), 1, pf); | |
fseek(pf, 0, SEEK_SET); | |
fread(&d, sizeof(s), 1, pf); | |
printf("%s %d %.1f", d.name, d.age, d.score); | |
fclose(pf); | |
pf = NULL; | |
return EXIT_SUCCESS; | |
} |