unix编程以及xv6系统浅谈(三)标准I/O库

350 阅读5分钟

3.1 缓冲

​ 对于标准IO库,它的操作是围绕流来,对于ascii字符,用一个字节表示,国际字符,一般是用多个字符表示,可以使用函数将流改变为宽定向的

int fwide(FILE* fp,int mode)
    mode<0	字节定向
    mode>0	宽定向
    mode=0	不设置,但返回标志该流定向的值

​ 打开一个流之后,返回一个指向FILE对象的指针,通常包括文件描述符,指向用于该流缓冲区的指针,缓冲区的长度,当前缓冲区中的字符数以及出错标志等等。

​ 3个标准IO流,stdin,stdout,stderr

​ 标准io提供下面3种缓冲

​ (1)全缓冲

​ 在填满缓冲区之后再进行操作

​ (2)行缓冲

​ 当遇到换行符的时候进行操作,同时只要填满了缓冲区,也会操作

​ (3)不带缓冲

​ 标准io库不对字符进行缓冲

​ 注意:

​ 标准错误是不带缓冲的

​ 若是指向终端设备的流,则是行缓冲;否则都是全缓冲的

​ 任何时候,都可以强制冲洗一个流

int fflush(FILE* fp)
    成功返回0,否则-1

3.2 流操作

​ 写操作统一为:

​ []->fp

​ 读操作统一为:

​ fp->[]

使用下面的函数打开一个标准IO流

//成功则返回文件指针,否则NULL
FILE* fopen(const char* pathname,const char* type)
    type:
			b 表示二进制
			r 读取
			w 写入,从头开始
			a 写入,往后面添加
			r+ 读写打开
			w+ 读写打开,但是若没有文件会创建文件,同时文件截断为0
			a+ 文件尾打开,每次写都会写到文件的尾端!
FILE* freopen(const char* pathname,const char* type,FILE* fp)
    在一个指定的流上打开一个指定的文件
FILE* fdopen(int fd,const char* type)
    在一个文件描述符上打开一个文件流,注意该方法不会截断文件,因为描述符已经打开了

​ 关闭文件的方法如下

int fclose(FILE* fp)
    成功,返回0,否则,返回EOF(-1)
    在文件被关闭之前,冲洗缓冲区中的输出数据,缓冲区中的任何输入数据被丢弃。
    当一个进程正常终止时,则所有带未写缓冲数据的标准IO流都被冲洗,所有打开的标准IO流都被关闭

3.2.1 字符操作

读取一个字符

//返回值都是读取到的字符,出错则返回EOF,文件结尾也会返回EOF,所以无法判断出错
int getc(FILE* fp)
    最快,可以被当作宏!
int fgetc(FILE* fp)
int getchar(void)
    从文件输入流中读取

​ 由于出错或者文件结尾都会返回-1,需要判断出错

int ferror(FILE* fp)
    判断读取文件出错,出错则返回真,否则0
int feof(FILE* fp)
    判断读取到文件结束,结束则返回真
void clearerr(FILE* fp)
    清楚上面两个标记
int ungetc(int c,FILE* fp)
    将字符压入流中,成功则返回c,否则返回EOF
    压入的字符可以时除了EOF之外的任意字符,不一定要读出的,到文件结尾再压入一个则会清楚EOF标志!

​ 输出一个字符的操作为:

//成功则返回c,否则返回EOF
int putc(int c,FILE* fp)
    同样,宏
int fputc(int c,FILE* fp)
int putchar(int c)
	输出到输出流

3.2.2 行的流操作

//成功则返回buf,否则到文件结尾或者出错,返回NULL
char* fgets(char* buf,int n,FILE* fp)
    每次都会读取一行,\n也会输入到缓冲区中,但是大小不会超过n,注意结尾会加NULL,所以字符数为n-1
	若有问题,则下次会继续该行
char* gets(char* buf)
    不检查长度,容易有bug,同时该函数不会将\n存入缓冲区中
//成功则返回非负值,否则返回EOF
int fputs(const char* str,FILE* fp)
    并不会输出行,即读取到\n也不会结束,NULL结尾不会写出
int puts(const char* str)
    将一个以NULL结尾的字符串写出道标准输出,不会到\n就结束,但是每次写完后,会再将一个\n写入到标准输出

3.2.3 二进制IO

//返回读或写的对象数
size_t fread(void* ptr,size_t size,size_t nobj,FILE* fp)
    size:	每个数组元素的大小,即sizeof(ptr[0])
    nobj:	为欲操作的元素个数,即sizeof(ptr)  //如果为数组的话
    若返回值小于nobj可能为EOF或者出错
size_t fwrite(const void* ptr,size_t size,size_t nobj,FILE* fp)
    写入时的返回值小于nobj则一定时出错

3.2.4 定位流

long ftell(FILE* fp)
    成功则返回文件位置,出错返回—1
int fseek(FILE* fp,long offset,int whence)
    成功则返回0,否则返回-1
    功能类似于lseek,注意返回值不同,而且由于缓冲区的存在不一定完全相同的文件偏移量
    offset:		<0 前移
    			>0 后移
    whence:	(同lseek)
				SEEK_SET(0)	开始位置
				SEEK_CUR(1) 当前位置
				SEEK_END(2) 结尾位置
void rewind(FILE* fp)
    将一个流设置到文件起始位置

3.2.5 格式化IO

​ 写操作(格式化输出)[格式化内容]->(fp)等目标

//成功则返回输出字符,出错则返回-(不一定-1)
int printf(const char* format,...)
int fprintf(FILE* fp,const char* format,...)
	格式化写入文件
int dprintf(int fd,const char* format,...)
   	写入到文件描述符的文件中
//成功返回存入数组的字符数,否则返回-
int sprintf(char* buf,const char* format,...)
    写入到buf指向的地址中,该函数没有边界检查,会再数组的末尾加一个NULL,但是不包括在返回值中
//返回存入数组的字符数,否则返回-
int snprintf(char* buf,size_t n,const char* format,...)
    写入但是带边界检查

​ 读操作(格式化输入)(fp)等内容->[格式化内容]

//返回输入项数,否则返回EOF(出错或者文件末尾)
int scanf(const char* format,...)
int fscanf(FILE* fp,const char* format,...)
	从文件中读入相关字符再格式化输入
int sscanf(const char* buf,const char* format,...)
    从数组中读取格式化内容输入到...中

3.2.6 内存流

​ linux 中可以将内存当作文件来操作,来使得那块文件操作异常迅速

//成功则返回流指针,否则返回NULL
FILE* fmemopen(void *buf,size_t size,const char*type)
    调用者通过buf和size这两个参数提供一段内存给该函数来实现内存文件流
    type的用法同open一样
    打开该文件后,文件的相关操作对其流都可以!