文件输入/输出
标准 I / O
-
C把文件(file)看作一系列连续的字节,C提供两种文件模式:文本模式和二进制模式
-
C程序会自动打开3个文件,他们被称为标准输入(standard input),标准输出(standart output) 和标准错误输出(standard error output)
标准文件 | 文件指针 | 通常设备 |
---|---|---|
标准输入(standard input) | stdin | 显示器 |
标准输出(standart output) | stdout | 显示器 |
标准错误输出(standard error output) | stderr | 显示器 |
- 在打开文件时一定要判断文件是否打开成功(即
if(fopen() == NULL) exit();
),因为一旦打开失败,后续操作就都没法进行了,往往以“结束程序”告终。
标准I / O的机理:
step1:fopen()不仅打开一个文件,还创建了缓冲区,以及一个管理记录的结构体FILE(包括文件名、文件状态、当前读写位置等),返回的fp指针指向该结构体:这一过程称为 fopen()打开了一个流,文本流(以文本模式打开文件),二进制流(以二进制模式打开)
step2:初始化结构和缓冲区后,输入函数从缓冲区读取数据(读到文件结尾返回EOF),输出函数把数据写入缓冲区(缓冲区满后拷贝至文件)
stdio.h 系列所有的输入函数都使用相同的缓冲区,每次都从上一函数停止位置开始
文件 I / O
fopen() / fclose()
函数 | 函数原型 | 功能 | 备注 |
---|---|---|---|
fp = fopen(“filename”, mode); | FILE * fopen ( const char * filename, const char * mode ); |
返回一个文件指针: FILE * fp 指向一个记录文件信息的数据结构 |
|
fclose(fp); | int fclose ( FILE * stream ); |
关闭成功返回 0;失败返回EOF(-1),磁盘以满,移动硬盘被移除或出现I/O错误,都会导致失败 |
mode模式字符串:
getc() / putc()
函数 | 函数原型 | 功能 | 备注 |
---|---|---|---|
ch = getc(fp) | int getc(FILE *stream) |
从fp指定文件中获取一个字符,读到文件结尾返回EOF | getc(stdin) == getchar(); |
putc(ch, fp) | int putc(int char, FILE *stream) |
把ch放入fp指向文件 | putc(ch, stdout) == putchar(); |
code 1:
char ch;
while((ch = getc(stdin)) != EOF){
putc(ch, stdout);
}
fprintf() / fscanf()
函数 | 函数原型 | 功能 | 备注 |
---|---|---|---|
fscanf(fp, “value = %d”, &x) | int fscanf(FILE *stream, const char *format, ...) |
→ fp 中内容写入 x | fscanf(stdin, “%d”, &x); == scanf("%d", &x); |
fprintf(fp, “%s\n”, str) | int fprintf(FILE *stream, const char *format, ...) |
← 将 str 写入 fp | fprintf(stdout, “%s”, str); == printf("%s", std); |
fgets() / fputs()
函数 | 函数原型 | 功能 | 备注 |
---|---|---|---|
fgets() | char *fgets(char *str, int n, FILE *stream) |
读取文件中字符串,直到:第一个换行符 或 文件结尾 或 n-1个字符, 然后添加’\0’ | 不处理 ‘\n’ |
fputs() | int fputs(const char *str, FILE *stream) |
将字符串打印到文件中 |
随机访问(控制文件指针的方法):fseek() / ftell()
函数 | 函数原型 | 功能 | 备注 |
---|---|---|---|
fseek() | int fseek(FILE *stream, long int offset, int whence) |
将光标移动到文件某位置,成功返回0 | 参数2是相对参数3的偏移量(offset) |
ftell() | long int ftell(FILE *stream) |
返回当前位置 |
fseek的第三个参数包括:
SEEK_SET
开始,SEEK_CUR
当前,SEEK_END
结束,旧版可用0L, 1L, 2L代替
- code
FILE* fp = fopen("test.txt", "r");
printf("%d\n", fseek(fp, 0L, SEEK_END));
printf("last = %d\n", ftell(fp));
- output:
随机访问(针对大文件:字节数超过long范围) fgetpos() / fsetpos()
上面fseek和ftell只能返回long类型,文件大小可能超过long的范围,所有用fgetpos() / fsetpos()来定位大文件
函数 | 函数原型 | 功能 | 备注 |
---|---|---|---|
fsetpos() | int fsetpos(FILE *stream, const fpos_t *pos) |
定位光标,偏移量为 *pos指向的 fpos_t类型数据 成功返回0 | |
fgetpos() | int fgetpos(FILE *stream, fpos_t *pos) |
将文件大小描述放到 *pos指向的位置 成功返回0 |
fpos_t (file position type):派生类型,可以用结构体实现?
其他 I / O 函数
一般都是成功返回0,不成功返回非零值:EOF(-1)
函数 | 函数原型 | 功能 | 备注 |
---|---|---|---|
ungetc() | int ungetc(int c, FILE* fp) |
撤回 上一句getc() | |
fflush() | int fflush(FILE* fp) |
刷新缓冲区:将缓冲区剩余内容发送到fp | |
setvbuf() | int setvbuf(FILE* fp, char * buf, int mode, size_t size); |
创建缓冲区 | mode见 [1]:三种缓冲区 |
[1]:三种缓冲区:
缓冲区类别 | mode | 描述 |
---|---|---|
完全缓冲(Full Buffer) | _IOFBF | 缓冲区满时刷新 |
行缓冲(Line Buffer) | _IOLBF | 缓冲区满时 或 写入换行符 时刷新 |
无缓冲(No Buffer) | _IONBF |
二进制 I / O
当你具有数组或结构时,仅将字符和字符串写入文件可能会变得乏味。
要将整个内存块写入文件,有以下二进制函数: