本章用于解析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. IO操作之BIO、NIO、AIO

    一.BIO Blocking IO: 同步阻塞的编程方式. BIO编程方式通常是在JDK1.4版本之前常用的编程方式.编程实现过程为:首先在服务端启动一个ServerSocket来监听网络请求,客户端 ...

  2. VS下设置dll环境变量目录的方法

    项目=>属性=>Debugging PATH=路径

  3. [Java复习] 缓存Cache part2

    7. Redis持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的? 为什么要持久化? 如果只是存在内存里,如果redis宕机再重启,内存数据就丢失了,所以要用持久化机 ...

  4. 【转载】 什么是P问题、NP问题和NPC问题

    原文地址: http://www.matrix67.com/blog/archives/105 转载地址: https://www.cnblogs.com/marsggbo/p/9360324.htm ...

  5. Ubuntu16.04 + cuda9.0 +cudnn7.1(转载)

    转载一个详细可用的ubuntu16.04+cuda9.0+cudnn7.1教程. 0 - 参考材料 https://blog.csdn.net/Umi_you/article/details/8026 ...

  6. Elasticsearch(ELK)集群搭建

    一.前言 Elasticsearch是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储.检索数据:本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据.Elasticsearch也使用 ...

  7. Canal——Canal-Adapter源码在IDEA部署运行

    一.下载源码 下载地址:https://github.com/alibaba/canal 我这里用的是canal-1.1.4版本 源码结构 client-adapter项目就是本次要部署运行的 源码导 ...

  8. pycurl模块

    pycurl的使用 pycurl是curl的一个python版本. pycurl的使用说明: pycurl的使用主要是一些参数的设定. 1,c.setopt(pycurl.URL,myurl) 设定链 ...

  9. 【Leetcode_easy】1103. Distribute Candies to People

    problem 1103. Distribute Candies to People solution:没看明白代码... class Solution { public: vector<int ...

  10. 第二十三章 多项目集中权限管理及分布式会话——《跟我学Shiro》

    二十三章 多项目集中权限管理及分布式会话——<跟我学Shiro> 博客分类: 跟我学Shiro 跟我学Shiro  目录贴:跟我学Shiro目录贴 在做一些企业内部项目时或一些互联网后台时 ...