unix环境下c语言I/O总结

发现自己在写代码的时候老是要去重复的查询各种I/O函数的原型,在这里把unix环境下经常用到的I/O函数进行总结

unix环境下I/O函数分三个级别,第一级别是最底层的brk()与sbrk()函数,用的较少,这里不做多的讨论;

 

第二级别的是linux提供的系统调用,操作主要面向文件描述符,如open(),read(),write(),close()函数,不带缓冲;包含头文件为<fcntl.h>与<unistd.h>

  int open(const char* path,int oflag, ... /*mode_t mode*/);成功返回文件描述符,失败返回-1。

  在系统中定义了很多oflag常量,常用的有O_CREAT,O_RDONLY,O_WRONLY,O_RDWR,O_EXEC,O_APPEND,O_EXCL等等,其中需要注意的是O_CREAT|O_EXCL这个组合,表示如果文件已经存在,则出错,不存在则创建新的文件,这个主要非常常用。

  ssize_t read(int fd,void* buf,size_t  nbytes);返回成功读取的字节数,到达文件尾返回0,失败返回-1。

 

  ssize_t write(int fd,void* buf,size_t  nbytes);返回成功写入的字节数,到达文件尾返回0,失败返回-1。

 

第三个级别便是c语言自带的标准I/O库,而标准库操作面向流。我认为流就是经过包装的文件描述符,带有缓冲区,等等。通常采用read()和write()函数来实现,带缓冲,分为全缓冲,行缓冲;通常每次标准库刷新缓冲区的时候都会调用一次write()邓处理数据。

标准IO库分为每次一个字符的I/O,主要函数:

  输入:

    int getc(FILE* fp); int fgetc(FILE* fp); int getchar(); 函数若成功,把下一个字符转换为int并返回, 若失败则返回EOF。这里需要特别说明下的是GETC()通常被实现为宏,则他的速度更快。

 这里为了区别是错误返回还是到达文件末尾,提供了两个函数: int ferror(FILE* fp) 和 int feof(FILE* fp),条件真返回非0,else返回0。

    同时标准库还提供了函数int ungetc(int c,FILE* fp) 可以将从文件流中读取的字符重新押送回文件流中。该函数在我们需要取出一个字符判断是否有用,再对其进行处理的时候非常方便。

  

  同样的与输入相对应的有3个字符输出函数:int putc(int c, FILE* fp)(通常采用宏实现), int fputc(int c, FILE* fp), int putchar()。

第二种则是每次一行I/O:

  输入: char* fgets(char* buf,int n,FILE* fp); char* gets(char* buf); gets()容易产生缓冲区溢出,通常不推荐使用。成功函数返回buf, 失败或者达到尾端返回NULL。

    fgets以换行符标识结尾,最多读入n-1个字符,并且在末尾加上null。

  输出: int* fputs(char* str,FILE* fp); int puts(const char* str)

    fputs将一个以null结尾的字符写入文件流,不包括结尾的NULL,需要注意的是puts函数通常会在函数末尾多加一个额外的换行符。

第三种则是二进制I/O:

  size_t fread(void* ptr,size_t size,size nobj,FILE* fp);

  size_t fwrite(void* ptr,size_t size,size_t nobj,FILE* fp); 这两个函数的返回值都是成功读写的对象的个数,比如一个结构体等等。通常如果返回值小于nobj,则读写错误。

  通常输出size_t 格式的数据要用%zd。

  读写二进制数据可能存在不同系统之间的数据不兼容的情况,如系统的大端小端存储问题等等。

第四种是格式化I/O:

  这边是最常用的prinf与scanf()系列函数;这里我主要介绍:

  int fprintf(FILE *fp, const char* format, ...);

  int fdprintf(int fd,const char* format);

  int sprintf(char* buf,const char* format, ... );

  int snprintf(char* buf,size_t n,const char* format);这些函数中,sprintf()同样由于缓冲区溢出的危险被弃用,推荐使用snprintf()。需要注意的是printf函数是有返回值的,返回成功操作的字符数,或负值(失败)。这里有一点我常搞混,就是这fprintf()的参数,FILE指针通常是放在第一个,而fread()与fwrite()函数则把函数指针放在最后,比较蛋疼,老是记不清。

  同时,还有比较繁琐的就是关于printf的个是控制符,需要知道printf()默认右对齐,在类型标识符前有4个控制字段%[flags][fldwidth][precision][lendmodifier]convtype具体比较难说,可以查阅相关文档。

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

  int sscanf(const char* buf, const char* format, ... );同样需要注意返回值,成功返回输入的项数,失败返回EOF。

  这里关于scanf()有一个个人觉得比较重要的应用就是清楚输入缓冲区。scanf("%*[]");这里'*'表示抑制转换,即接受输入,但是并不对输入的数据赋值到任何参数。[]表示接受匹配括号内部的正则表达式的任何值。

接下来比较重要的还有关于文件偏移量的一些函数,下篇文章介绍。

 

posted on 2015-01-29 14:38  deng_yong  阅读(330)  评论(0编辑  收藏  举报