打开流
// return: `FILE *` or `NULL`
FILE *fopen(char const *name, char const *mode);
mode的选项: “r”, “w”, “a”, “rb”, “wb”, “ab”, “a+”
使用:
FILE *input;
input = fopen("file", "r");
if(input == NULL){
perror("can not open file");
exit(EXIT_FAILURE);
}
以指定文件名和模式重新打开 stream:
// return: `FILE *stream` or `NULL`
FILE *freopen(char const *filename, char const *mode, FILE *stream);
关闭流
// return: `0` or `EOF`
int fclose(FILE *f);
使用:
if(fclose(input) != 0){
perror("fclose %s", input);
exit(EXIT_FAILURE);
}
字符I/O
// stream/stdin ==> character
// return: 函数执行成功会返回读取的字符,失败返回`EOF`
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);
不用char
作为返回值类型的原因是为了返回EOF
(end of file),EOF作为常量,它的值在任何可能出现的字符范围之外。
// character ==> stream/stdout
// return: `0` or `EOF`
int fputc(int character, FILE *stream);
int putc(int character, FILE *stream);
int putchar(int character);
在写入流之前,character会被剪裁为无符号字符型值。
getc
, putc
, getchar
, putchar
是通过#define
定义的宏。
int ungetc(int character, FILE *stream);
ungetc
把一个先前读入的字符返回的流中,这样它可以在以后被重新读入 比如:
/*
** 从一串标准输入中读取的数字转化为整数
*/
#include <stdio.h>
#include <ctype.h>
int read_int(){
int ch;
int value = 0;
while((ch = getchar()) != EOF && isdigit(ch)){
value *= 10;
value += ch - '0';
}
// 把非数字字符退回的流中,这样它不会丢失
ungetc(ch, stdin);
return value;
}
未格式化的行I/O
// stream/stdin ==> buffer
// return: 如果在任何字符读取前就到达了文件末尾,返回`NULL`, 否则返回buffer
char *fgets(char *buffer, int buffer_size, FILE *stream);
char *gets(char *buffer);
当fgets
读取到一个换行符并存储的buffer之后就不再读取,如果buffer中的字符数达到buffer_size-1时它也停止读取,任何情况下,NUL
字节会被添加到buffer所存储数据的末尾。
fgets
无法把字符读入到长度小于两个字节的buffer,因为其中一个字节需要为NUL
字节保留
gets
从stdin
读取一行输入时,并且不在buffer中存储结尾的换行符。
// buffer ==> stream/stdout
// return: 执行错误返回`EOF`,否则返回非负值
int fputs(char const *buffer, FILE *stream);
int puts(char const *buffer);
传递给fputs
的buffer预期以NUL
结尾,buffer中可以有换行符(\r\n
),即可以一次可以写入多行。
puts
写入一个字符串时,它在字符串写入之后向输出在添加一个换行符(即不需显式的\n
)。
格式化的行I/O
每个原型中的省略号表示一个可变长度的指针列表,从输入转换而来的值逐个存储到这些指针指向的内存地址。
// stdin/stream/string ==> ...
// return: 在任何情况下,函数返回被转换的输入值的数目;如果在任何输入值被转换之前文件就已到达末尾,函数就返回常量值`EOF`
int scanf(char const *format, ... );
int fscanf(FILE *stream, char const *format, ... );
int sscanf(char const *string, char const *format, ... );
当格式化字符串达到末尾或者读取的输入不再匹配格式字符串指定的类型时,输入就停止。
scanf
函数家族中的format字符串参数可能包含的内容:
- 空白字符: 它们与输入中的零个或多个空白字符匹配
- 格式代码: 它们指定函数如何解释接下来的输入字符
- 其他字符: 当任何其他字符出现在格式字符串时,下一个输入字符必须与它匹配;如果匹配,该输入字符随后就被丢弃,如果不匹配,函数就不再读取直接返回
// ... ==> stdout/stream/buffer
// return: 实际打印或存储的字符数
int printf(char const *format, ... );
int fprintf(FILE *stream, char const *format, ... );
int sprintf(char *buffer, char const *format, ... );
二进制I/O
// stream --> buffer
size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
// buffer --> stream
size_t fwrite(void *buffer, size_t size, size_t count, FILE *stream);
return: 函数返回实际读取或写入的元素(而非字节)数目,如果输入过程中遇到了EOF
或输出过程中出现错误,这个数字可能比请求的元素数目小。
刷新和定位函数
fflush
迫使一个输出流的缓冲区内的数据进行物理写入,不管缓冲区是否已经写满。
int fflush(FILE *stream);
在程序调试时可以用来在特定位置输出调试信息,而不是等待缓冲区写满之后才打印:
printf("something or other");
fflush(stdout);
随机访问I/O需要在读取或写入前先定位到文件中需要访问的位置来实现的。
long ftell(FILE *stream);
int fseek(FILE *stream, long offset, int from);
ftell
返回流的当前位置,即下一个读取或写入将要开始的位置距离文件起始位置的偏移量;在二进制流中,这个值就是当前位置距离文件起始位置之间的字节数;在文本流中,它不一定准确的表示当前位置和文本起始位置之间的字符数(因为有些系统将对行末字符进行翻译转换),但ftell
的返回值总是可以用于fseek
中,作为一个距离文件起始位置的偏移量。
fseek
在一个流中定位,这个操作将改变下一个读取或写入操作的位置。
from | 你将定位到 |
---|---|
SEEK_SET | 从流开始位置起offset个字节,offset非负 |
SEEK_CUR | 从流当前位置起offset个字节,offset可正可负 |
SEEK_END | 从流尾部位置起offset个字节,offset可正可负,如果它是正值,它将定位到文件尾的后面 |
以限制更严格的方式执行文件定位:
void rewind(FILE *stream);
int fgetpos(FILE *stream, fpos_t *position);
int fsetpos(FILE *stream, fpos_t const *position);
rewind
将读/写指针设置回流的起始位置,它同时清除流的错误提示标志。
fgetpos
在position
中存储文件的当前位置。
fsetpos
把文件位置设置为存储在position
的值。
使用一个fgetpos
设置的position
的唯一安全的用法是把它作为参数传递给后续的fsetpos
待补充
feof(fp) //当文件结束时得到不为0的数
ferror(fp) //当文件出错时得到不为0的数
fileno(fp) //得到文件描述符
BUFSIZE //正常I/O缓冲区的大小,一般为512或1024
- older
- Newer