IO库函数和系统调用
系统调用时文件操作的基础。每个I/O库函数的根都在对应的系统调用函数中。
-
显示文件内容
-
系统调用
#include<fcnt1.h> int main(int argc, char *argv[]) { int fd; int i,n char buf[4096]; if(argc<2)exit(1); fd=open(argv[1],O_RDONLY); if(fd<0)exit(2); while(n=read(fd,buf,4096)){ for(i=0;i<n;i++){ write(1,&buf[i],1); } } }
-
I/O库函数
#include<stdio.h> int main(int argc, char *argv[]) { FILE *fp; int c; //for EOF of stdin if(argc<2)exit(1); fp=open(argv[1],"r"); if(fd==0)exit(2); while((c=fgetc(fp))!=EOF){ putchar(c); } }
-
系统调用是逐字节的,而I/O库采用的是字节流。从实现这个任务的区别就可见系统调用的效率相较而言是更低的。
I/O库函数的算法和模式
fopen
FILE *fopen(const char *filename, const char *mode)
- b 二进制模式,默认为文本模式
- r 打开,文件必须存在
- w 创建,截断
- a 追加,创建
- r+ r和写入
- w+ w和读取
- a+ a和读取
fread()
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
存储数据的地址、读取元素的大小、读取多少个元素、文件指针
fwrite()
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
待写入数据的地址、写入元素的大小、写入多少个元素、文件指针
fgetc()
int fgetc(FILE *stream)
如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。
fputc()
int fputc(int char, FILE *stream)
如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。
ungetc()
int ungetc(int char, FILE *stream)
把字符 char(一个无符号字符)推入到指定的流 stream 中,以便它是下一个被读取到的字符。
换言之,ungetc不对文件进行操作,只是针对文件流
fgets()
char *fgets(char *str, int n, FILE *stream)
fgets()读到回车换行就会结束读取
str 存储地址
int n 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。
如果发生错误,返回一个空指针。
fputs()
int fputs(const char *str, FILE *stream)
str 是一个数组,包含了要写入的字符序列。
fscanf()
int fscanf(FILE *stream, const char *format, 存储地址...)
format -- 这是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符 和 format 说明符。
format 说明符形式为 [=%[*][width][modifiers]type=]
如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。
scanf其实是fscanf(stdin,...)
fprintf()
int fprintf(FILE *stream, const char *format, 待输出数据...)
format 是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier
如果成功,则返回写入的字符总数,否则返回一个负数。
printf其实是fprintf(stdout,...)
sscanf()
int sscanf(const char *str, const char *format, ...) 从str字符串读取格式化输入。
sprintf()
int sprintf(char *str, const char *format, ...) 发送格式化输出到 str 所指向的字符串。
fseek()
int fseek(FILE *stream, long int offset, int origin)
设置流 stream 的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 origin 位置查找的字节数。
origin:
- SEEK_SET 文件的开头
- SEEK_CUR 文件指针的当前位置
- SEEK_END 文件的末尾
ftell()
long int ftell(FILE *stream)
该函数返回位置标识符的当前值。如果发生错误,则返回 -1
与SEEK_END 一起,可以计算文件的大小
rewind()
void rewind(FILE *stream)
相当于 fseek(fp,0,SEEK_SET)
setvbuf()
int setvbuf(FILE *stream, char *buffer, int mode, size_t size)
setvbuf(),设置文件缓冲区,而不必使用fopen()函数打开文件时设定的默认缓冲区,从而控制缓冲区大小、定时刷新缓冲区、改变缓冲区类型、删除流中默认的缓冲区、为不带缓冲区的流开辟缓冲区等。
buffer : 分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。
size : 缓冲区大小
mode :
_IOFBF | 全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。 |
---|---|
_IOLBF | 行缓冲:对于输出,数据在遇到换行符或者在缓冲填满时被写入,具体视情况而定。对于输入,缓冲会在请求输入且缓冲为空时被填充,直到遇到下一个换行符。 |
_IONBF | 无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。 |
fflush()
int fflush(FILE *stream)
fflush()的作用是用来刷新缓冲区
fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃
fflush(stdout)刷新标准输出缓冲区,把输出缓冲区里的东西强制打印到标准输出设备上。
如果成功,该函数返回零值。如果发生错误,则返回 EOF
文件流缓冲方案
- 无缓冲:从非缓冲流中写入或读取的字符将尽快单独传输到文件或从文件中传输。例如,文件流stderr通常无缓冲。到stderr的所有输出都会立即发出
- 行缓冲:遇到换行符时,写入行缓冲流的字符以块的形式传输。例如,文件流stdout通常是行缓冲,逐行输出数据。
- 全缓冲:写入全缓冲流或从中读取的字符以块大小传输到文件或从文件传输。这是文件流的正常缓冲方案。