本章用于解析C语言标准I/O库,之所以在UNIX类系统的编程中会介绍C语言标准库,主要是因为UNIX和C之间具有密不可分的关系。

标准I/O库相比于操作系统的I/O库,具有更高的效率和可移植性,前者是因为标准I/O库提供了缓冲和块长度优化功能,后者是因为使用标准I/O库的代码不仅能在各UNIX系统上移植,也能在支持标准C的非UNIX系统上移植。


一、基本概念

流和FILE对象

UNIX系统I/O是建立在文件描述符的抽象概念上的,而标准I/O库则是建立在流的概念上的。当使用标准I/O库打开一个文件进行读写时,会创建一个流,该流与将要打开的文件进行关联,通过对抽象流的读写来间接读写文件。

标准输入、标准输出和标准错误

UNIX系统的shell中会默认为进程打开3个文件描述符:标准输入0、标准输出1和标准错误2。但它们是文件描述符的可阅读宏,ISO C标准I/O是无法使用的,为此ISO C标准I/O定义了三个另外的名字来引用它们,分别是:stdin、stdout、strerr。它们在头文件<stdio.h>中被定义。实际上STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO分别对应stdin、stdout、strerr。

缓冲

对于UNIX系统来说,标准I/O库最终是建立在系统调用的read()和write()上的。而UNIX系统的read()和write()是不带缓冲的。为了提供效率,标准I/O库提供了缓冲管理。

对于需要立即执行完成的标准读写操作,我们可以强制使用fflush()函数来刷新流的缓冲区。其函数声明如下:

 #include <stdio.h>

 int fflush(FILE *__stream);

 /* 例子 */
fflush(stream);

二、标准I/O函数

 #include <stdio.h>

 /* 1. 打开流 */
FILE *fopen(const char * __filename, const char * __modes);
FILE *freopen(const char * __filename, const char * __modes, FILE * __stream);
FILE *fdopen(int __fd, const char *__modes);
/* fopen()用于打开指定路径的文件 */
/* freopen()在指定流上关联指定的文件。如流已经打开,则重新打开;如流已定向,则清除定向。该函数通常用来重定向标准输入、标准输出和标准错误 */
/* fdopen()用于将一个已有的文件描述符与一个标准I/O流关联。该函数常在创建管道或者网络socket得到的描述符上 */ /* 2. 读/写流 */
/* 2.1 字节I/O */
int getc(FILE *__F);
int fgetc(FILE *__F);
int getchar(void);
/* 这三个函数一次只读取一个unsigned char,然后转换为int,在读取一个字符后,流自动移动到下一个字符,然后再次调用函数时会返回相对于上一次字符的下一个位置上的字符 */ int putc(int __c, FILE *__F);
int fputc(int __c, FILE *__F);
int putchar(int __c);
/* 这三个函数成功返回__c,失败返回NULL。这三个函数一次只写入一个unsigned char,如果传递的值超过256的int类型实参给函数,那么超出范围的会被截断 */ /* 2.2 行I/O,遇到换行符位置 */
char *gets(char *__s);
char *fgets(char* __s, int __n, FILE* __F);
/* gets()函数建议不要使用,因为此函数会导致缓存区溢出 */ int fputs(const char* __s, FILE* __F);
int puts(const char* __s); /* 2.3 二进制I/O */
size_t fread(void* __ptr, size_t __size, size_t __n, FILE* __F);
size_t fwrite(const void* __ptr, size_t __size, size_t __n, FILE* __F);
/* 这两个函数的返回值都是读或写的对象数量。参数中的__size是对象的大小,即sizeof计算得到的大小;__n是对象的数量 */ /* 3. 定位流 */
int fseek(FILE *__F, long int __off, int __whence); /* 4.关闭流 */
int fclose(FILE *__F);

代码中的fopen()函数的第二个参数有以下几种模式:

r 以只读方式打开文件,该文件必须存在

r+ 以读/写方式打开文件,该文件必须存在

rb+ 以读/写方式打开一个二进制文件,只允许读/写数据

rt+ 以读/写方式打开一个文本文件,允许读和写

w 打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件

w+ 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件

a 以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF 符保留)

a+ 以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF符不保留)

wb 以只写方式打开或新建一个二进制文件,只允许写数据

wb+ 以读/写方式打开或新建一个二进制文件,允许读和写

wt+ 以读/写方式打开或新建一个文本文件,允许读和写

at+ 以读/写方式打开一个文本文件,允许读或在文本末追加数据

ab+ 以读/写方式打开一个二进制文件,允许读或在文件末追加数据

常用的有r+,rt+,at+等

代码中的gets()会导致缓存区溢出,尽量不要使用。同样会导致缓存区溢出的函数有strcpy()、strcat()等

示例代码:

 FILE *stream = NULL;
char buf[] = "Hello World\n";
int ret = ; stream = fopen("a.txt", "w+"); fwrite(buf, sizeof(char), strlen(buf), stream);
fseek(stream, , SEEK_SET); /* whence可选为SEEK_SET、SEEK_CUR、SEEK_END */
memset(buf, , sizeof(buf));
ret = fread(buf, sizeof(char), sizeof(buf), stream);
if (ret) {
printf("Read %d Bytes From a.txt, Content: %s\n", ret, buf);
} fclose(stream);

下一章  第七章:进程环境

第五章:标准I/O库的更多相关文章

  1. 《UNIX环境高级编程》(APUE) 笔记第五章 - 标准I/O库

    5 - 标准I/O库 Github 地址 1. 标准 I/O 库作用 缓冲区分配 以优化的块长度执行 I/O 等 使用户不必担心如何选择使用正确的块长度 标准 I/O 最终都要调用第三章中的 I/O ...

  2. UNIX系统高级编程——第五章-标准I/O库-总结

    基础: 标准I/O库在ANSI C中定义,可移植在不同的系统 文件指针(FILE):标准I/O库操作的不是文件描述符,而是流.FILE文件指针包含的是维护流所需的信息 通过函数fileno获取流的文件 ...

  3. 《APUE》-第五章标准IO库

    大多数UNIX应用程序都使用I/O库,本章说明了该库所包含的所有函数,以及某些实现细节和效率方面的考虑.同时需要重点关注标准I/O使用了缓冲的技术,但同时也是因为它的出现,产生了很多细节上的问题. 流 ...

  4. UNIX环境高级编程 第5章 标准I/O库

    本章是关于C语言标准I/O库的,之所以在UNIX类系统的编程中会介绍C语言标准库,主要是因为UNIX和C之间具有密不可分的关系.由于UNIX系统存在很多实现,而每个实现都有自己的标准I/O库,为了统一 ...

  5. 第五章 标准I/O

    5.1 引言 本章说明标准 I/O 库.因为不仅在 UNIX 上,而且在很多操作系统上都实现了此库,所以它由 ISO C 标准说明. 标准 I/O 库处理很多细节,例如缓冲区分配,以优化长度执行 I/ ...

  6. apue学习笔记(第五章 标准I/O)

    本章讲述标准I/O库 流和FILE对象 对于标准I/O库,它们的操作是围绕流进行的.流的定向决定了所读.写的字符是单字节还是多字节的. #include <stdio.h> #includ ...

  7. APUE之第5章——标准I/O库

    一.知识回顾:文件I/O 文件 I/O 是不带缓冲的 I/O(unbuffered I/O),指每个 read 和 write 都调用内核中的一个系统调用. 对于内核而言,所有打开的文件都通过文件描述 ...

  8. Python爬虫学习==>第五章:爬虫常用库的安装

    学习目的: 爬虫有请求库(request.selenium).解析库.存储库(MongoDB.Redis).工具库,此节学习安装常用库的安装 正式步骤 Step1:urllib和re库 这两个库在安装 ...

  9. 第5章标准I/O库总结

    1 fwide函数试图设置流的定向(流的定向决定了读写单字节还是多字节字符) int fwide(FILE *fp,int mode) 宽定向返回正值,字节定向返回负值,为定向返回0 已定向流不会改变 ...

随机推荐

  1. (转)kafka 详解

    kafka入门:简介.使用场景.设计原理.主要配置及集群搭建(转) 问题导读: 1.zookeeper在kafka的作用是什么? 2.kafka中几乎不允许对消息进行"随机读写"的 ...

  2. createElement与createDocumentFragment的一些小区别

    在DOM操作里,createElement是创建一个新的节点,createDocumentFragment是创建一个文档片段. 网上可以搜到的大部分都是说使用createDocumentFragmen ...

  3. BaggingClassifier

      写在前面 Ensemble methods 组合模型的方式大致为四个:/bagging / boosting / voting / stacking ,此文主要简单叙述 bagging算法. 算法 ...

  4. ST Debug (printf) Viewer for Jlink

    Debug (printf) Viewer http://www.keil.com/support/man/docs/uv4/uv4_db_dbg_serialwin.htm Serial Windo ...

  5. How to transform the day time images to night time ? A series of paper review and some thinkings about this point.

    How to transform the day time images to night time ?  A series of paper review and some thinkings ab ...

  6. windows开机执行bat

    一.以windows下备份sql数据库为例,开机自动执行.bat脚本        1.新建dump.bat文件,文件中的代码如下:                set YYYYmmdd=%date ...

  7. JS 将页面上的表格导出为 Excel 文件

    如果在页面上展示了一个表格,想把这个表格导出为Excel文件,那么在要求不高的情况下,可以直接利用 JavaScript 的 Blob 和 Object URL 特性将表格导出.不过,这就是利用了 E ...

  8. Borg、Omega和Kubernetes:谷歌十几年来从这三个容器管理系统中得到的经验教训 原创: 韩佳瑶 译 Docker 2016-03-23Borg、Omega和Kubernetes:谷歌十几年来从这三个容器管理系统中得到的经验教训 原创: 韩佳瑶 译 Docker 2016-03-23

    Borg.Omega和Kubernetes:谷歌十几年来从这三个容器管理系统中得到的经验教训 原创: 韩佳瑶 译 Docker 2016-03-23

  9. 监控、日志、APM整个监控体系思考 我为峰2014 简书作者 4.6092018-11-19 11:39打开App 序言

    监控.日志.APM整个监控体系思考 我为峰2014 简书作者 4.6092018-11-19 11:39打开App 序言

  10. transition css3 渐变效果

    div { width:100px; transition: width 2s; -moz-transition: width 2s; /* Firefox 4 */ -webkit-transiti ...