Unix环境高级编程读书笔记(3)

来源:互联网 发布:外贸数据应用 编辑:程序博客网 时间:2024/06/09 19:27
*、标准I/O库处理很多细节,如缓冲区分配、以优化的块长度执行I/O等,这些处理使用户不必担心如何选择使用正确的块长度,这使得它便于
用户使用
*、对于标准I/O库,它们的操作是围绕流进行的
*、对于ASCII字符集,一个字符用一个字节表示,对于国际字符集,一个字符可用多个字节表示;标准I/O文件流可用于单字节或多字节字符解,
流的定向决定了所读、写的字符是单字节还是多字节,当一个流最初被创建时,它并没有定向
*、当打开一个流时,标准I/O函数fopen返回一个指向FILE对象的指针,该对象通常是一个结构,它包含了标准I/O库为管理该流需要的所有信息,
包括用于实际I/O的文件描述符、指向用于该流缓冲区的指针、缓冲区的长度、当前在缓冲区中的字符数以及出错标志等。
*、除非流引用终端设备,否则按系统默认,流被打开时是全缓冲的,若流引用终端设备,则该流是行缓冲的。
*、当标准输入、输出连至终端时,它们是行缓冲的,行缓冲的长度是1024字节,标准错误是不带缓冲的,普通文件按系统默认是全缓冲的


1、标准I/O流可以是单字节或者是多字节字符集,流定向决定了字符串读写时是单字节还是多字节,当流建立的时候,没有定向,当一个多字
节I/O函数使用在流上面时,流被设置为宽定向,当一个字节I/O函数使用在流上面的时候,流被设置为字节定向,这边所提到的流是尚未定义定向的。
int fwide(FILE*stream,int mode);
如果mode为负数,则尝试设置流为字节定向;
如果mode为正数,则尝试设置流为宽定向;
如果mode为0,则不尝试设置流定向,但是仍会返回流的定向;
fwide不能改变已经定向的流定向


2、标准库中提供了三种类型的缓冲:全缓冲、行缓冲、不缓冲
术语冲洗,是标准I/O缓冲区的写操作
全缓冲:在这种情况下,在填满标准I/O缓冲区后才进行实际I/O操作,对于驻留在磁盘上的文件通常是由标准I/O库实施全缓冲的。在一个流上
执行第一次I/O操作时,相关标准I/O函数通常用malloc获得需使用的缓冲区;
行缓冲:在这种情况下,当在输入和输出中遇到换行符时 ,标准I/O库执行I/O操作,当涉及一个终端时,通常使用行缓冲;
对于行缓冲有两个限制
1)行缓冲区的长度是固定的,所以只要填满了缓冲区,即使还没有写一个换行符,也进行I/O操作
2)当有scanf函数需要从缓冲区中读取数据时,缓冲区中的数据会被取出
不带缓冲:标准错误流stderr通常是不带缓冲的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个换行符
注意:若时指向终端设备的流,是行缓冲,否则是全缓冲






下列函数可以用来更改缓冲类型
void setbuf(FILE*stream,char *buf);
int setvbuf(FILE*stream,char*buf,int mode,size_t size);
setbuf:用于开关缓冲,当将buf设置为nullptr时,关闭缓冲或者buf指向一个长度为BUFSIZE(stdio.h)的缓冲区
setvbuf:设置所需的缓冲类型
mode:可以选择的值如下
_IOFBF:全缓冲
_IOLBF:行缓冲
_IONBF:不缓冲
如果指定一个不缓冲的流,则可以忽略buf,size参数
如果指定全缓冲或者行缓冲,则可以指定一个缓冲区和长度,如果流的buf也设置为nullptr,则标准IO库自动分配一个BUFSIZE长度的缓冲区


3、int fflush(FILE*stream);
fflush:强制刷新一个流,该流所有未写的数据都被传送到内核中,当stream为nullptr时,所有打开的输出流都被刷新


4、FILE* fopen(const char*path,const char*mode);
FILE* fdopen(int fd,const char*mode);
FILE* freopen(const char*path,const char*mode,FILE*stream);
fopen:打开一个文件,并返回一个与之相关联的流
fdopen:通过文件描述符返回一个与之关联的流,其中mode可选的字符串于fopen相同,但不会有“文件不存在,则创建”之类的效果,因为有效的
fd保证了文件已经存在了;当fdopen创建的流被关闭的时候,文件描述符fd也会被关闭,另外mode与获取fd时选择的mode要兼容,假设使用open
获取fd时,设置为readonly,则此时设置r+会冲突


5、当我们打开一个流之后,可以选择三种无格式I/O类型进行读写
1)每次一个字符的I/O,每次可以读或者写一个字符,如果流是带缓冲的,I/O标准库会处理所有的缓冲
2)每次一行的I/O,可以使用fgets/fputs来读/写一行,每行以一个换行符终止
3)直接I/O,可以使用fread/fwrite支持这种I/O
getchar()<=>getc(stdin)
getc被实现为宏,因此不能将其作为函数指针传递
fgetc被实现为一个函数
当文件到达末尾或者发生错误时,都是返回EOF,为了分辨这种情况,使用以下两个函数来区分
int feof(FILE*stream);
int ferror(FILE*stream);
在大多数实现中,为每个流在FILE对象中维护了两个标志:
出错标志、文件结束标志,用clearerr函数可以清除该标志 
void clearerr(FILE *stream);
putc通常被实现为宏,而fputc被实现为函数


fgets指定读取的长度,如果一行超过这个长度,只读取部分,然后下次接着读取这一行。
gets是不建议使用的,容易造成overflow


6、size_t fread(void *ptr,size_t size,size_t nmemb,FILE*stream);
size_t fwrite(const void*ptr,size_t size,size_t nmemb,FILE*stream);
它们只能用于在同一系统上;
原因:1、在一个结构中,同一成员的偏移量在不同系统和编译程序的情况下偏移量可能不同
2、用来存储多字节整数和浮点值的二进制格式在不同的系统结构中也可能不同


fread:ptr指向欲存放读取进来的数据空间,读取字符数以参数size*nmemb决定
fwrite:ptr指向欲被写的数据的地址,写入的字符数以参数size*nmemb决定


7、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中,sprintf会自动在该数组尾端加一个null字节,但该字符不包含在返回值中,
sprintf可能会造成由buf指向的缓冲区溢出
int snprintf(char*buf,size_t n,const char*format,...);//指定了缓冲区的长度


int scanf(const char*format,...);
int fscanf(FILE*fp,const char*format,...);
int sscanf(const char*buf,const char*format,...);


8、内存流:相当于把一段内存映射成一个文件来操作
FILE*fmemopen(void*buf,size_t size,const char* mode);
FILE*open_memstream(char**ptr,size_t *sizeloc);
FILE*open_wmemstream(wchar_t**ptr,size_t*sizeloc);
fmemopen:mode和fopen的相同


第一个函数和后两个函数的区别:
1)后两个函数创建的流只能写打开
2)后两个函数不能指定自己的缓冲区,但可以访问缓冲区地址和大小
3)关闭流后需要自行释放缓冲区
4)对流添加字节会增加缓冲区的大小
0 0
原创粉丝点击