APUE 学习笔记(四) 标准I/O库

1.流与FILE对象

unix I/O系统调用都是针对文件描述符的

标准C的I/O函数都是针对流(文件指针)的,我们使用一个流与一个文件相关联

2.缓冲

标准I/O库提供缓冲的目的就是尽可能减少read和write系统调用的使用次数

标准I/O提供三种类型的缓冲:

(1)
全缓冲:在填满标准I/O缓冲区后才进行实际I/O操作,磁盘上的文件通常是全缓冲,第一次I/O操作时调用malloc获得需要使用的缓冲区

(2)行缓冲:输入输出遇到换行符时,标准I/O库执行I/O操作。涉及终端时(标准输入和标准输出)通常使用行缓冲

标准I/O库用来收集每一行的缓冲区的长度是固定的,只要填满了缓冲区,就一定会进行I/O操作

(3)不带缓冲:标准出错流stderr通常是不带缓冲的,这使得出错信息可以尽快显示出来

setbuf  setvbuf

使用标准I/O的一个优点就是无需考虑缓冲以及最佳I/O长度的选择

3.二进制I/O

(1)读或写一个二进制数组,例如,将一个浮点数组的第2-5个元素写至一个文件

float data[10];
fwrite(&data[2], sizeof(data[0]), 4, fp);

(2)读或写一个结构体


struct {
short count;
long total;
char name[NAMESIZE];
} item;

fwrite(&item, sizeof(item), 1, fp);

4.测试I/O性能


  #include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define BUFSIZE 1
//#define BUFSIZE 8
//#define BUFSIZE 64
//#define BUFSIZE 256
//#define BUFSIZE 1024
//#define BUFSIZE 4096
//#define BUFSIZE 9182

int main(int argc, char* argv[])
{
char buf[BUFSIZE];
int nbytes = 0;
/* unix read version */
/*
while ((nbytes = read(STDIN_FILENO, buf, BUFSIZE)) > 0) {
if (write(STDOUT_FILENO, buf, nbytes) != nbytes) {
fprintf(stderr, "write error\n");
}
}
if (nbytes< 0) {
fprintf(stderr, "read error\n");
}
*/

/* std c I/O version */
int c;
while ((c = fgetc(stdin)) != EOF) {
if (fputc(c, stdout) == EOF) {
fprintf(stderr, "fputc error\n");
}
}
if (ferror(stdin)) {
fprintf(stderr, "fgetc error\n");
}

return 0;
}

我们查看程序的测试文本: stat test.txt

得知:该测试文件为 259,546,640Byte, I/O块大小为 4096字节
























































BUFSIZE 用户CPU时间 系统CPU时间 时钟时间 系统调用数
1 30.302 555.702 588.962 259,546,640
8 3.672 71.468 75.741 32,443,330
64 0.460 9.165 9.877 4,055,417
256 0.108 2.600 3.011 1,013,854
1024 0.052 1.020 1.889 253,464
4096 0.016 0.512 1.649 63,366
9182 0.000 0.596 1.735 31,683
fgetc fputc 7.604 0.380 8.001  
 从上表可以看出:

(1) BUFSIZE直接决定了 系统调用数,所以使用unix I/O的关键在于选取最合适的缓冲区长度

(2)当BUFSIZE等于 文件
I/O块大小时,系统CPU时间出现最小值
,继续增加缓冲区长度对此时间几乎没有影响

(3)fgetc fputc标准I/O自行管理缓冲区,但是其时间都大于 unix
I/O最佳缓冲区时的时间值,使用标准I/O库时,系统会自动选取一个最佳I/O长度

一般依据文件的I/O块大小值,但是因为标准I/O的内部缓冲 和 unix I/O最佳缓冲区长度相等时,标准I/O库中有一个 外存文件==>
FILE内部缓冲 ==> 应用缓冲,

而Unix I/O 是直接 外存文件 ==> 应用缓冲, 两者虽然系统调用数相同,但是 标准I/O多了缓冲的操作,所以效率较低

时间: 2024-11-06 03:38:01

APUE 学习笔记(四) 标准I/O库的相关文章

APUE学习笔记:第五章 标准I/O库

5.1 引言 标准I/O库处理很多细节,例如缓冲区分配,以优化长度执行I/O等.这些处理不必担心如何使用正确的块长度.这使得它便于用户使用,但是如果不较深入地了解I/O库函数的操作,也会带来一些问题 5.2 流和FILE对象 对于ASCII字符集,一个字符用一个字节表示.对于国际字符集,一个字符可用多个字节表示.标准I/O文件流可用于单字节或多字节字符集. 流的定向决定了所读.写的字符是单字节还是多字节的.当一个流最初被创建时,它并没有定向.如若在未定向的流上使用一个多字节I/O函数,则将该流的

C++ Primer 学习笔记_13_标准模板库_list双向链表容器

C++ Primer 学习笔记_13_标准模板库_list双向链表容器 list容器实现了双向链表的数据结构,数据元素是通过链表指针串连成逻辑意义上的线性表,这样,对链表的任一位置的元素进行插入.删除和查找都是超快速的.下图是双向循环链表的结构示意图. list的每个节点有三个域:前驱元素指针域.数据域和后继元素指针域.前驱元素指针域保存了前驱元素的首地址:数据域则是本节点的数据:后继元素指针域则保存了后继元素的首地址.list的头结点的前驱元素指针域保存的是链表中尾元素的首地址,而list的尾

C++ Primer 学习笔记_10_标准模板库_map和set的对比

C++ Primer 学习笔记_10_标准模板库_map和set的对比   set multiset 创建 set<int> str multiset<string> str 插入 str.insert(8) str.insert("abc") 遍历 set<int>::iterator iter multiset< string >::iterator iter 输出 *iter *iter 删除 n = str.erase(8) 删除

C++ Primer(第五版)学习笔记_1_标准模板库--快速入门

C++ Primer(第五版)学习笔记_1_标准模板库--快速入门 欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 标准模板库(STL)提供三种类型的组件:容器.迭代器和算法,他们都支持泛型程序设计标准. 容器主要有两类:顺序容器和关联容器.顺序容器(vector.list.deque和string等)是一系列元素的有序集合.关联容器(set.multiset.map和multimap)包含查找元素的键值. 迭代器的作用是遍历容器. STL算法库包含四类算法:排序算法.不可变序算法.变序性算法

C++ Primer 学习笔记_14_标准模板库_bitset位集合容器

C++ Primer 学习笔记_14_标准模板库_bitset位集合容器 bitset容器是一个bit位元素的序列容器,每个元素只占一个bit位,取值为0或1,因而很节省内存空间.下图是一个bitset的存储示意图,它的10个元素只使用了两个字节的空间. 使用bitset需要声明头文件"#include <bitset>" 1.创建bitset对象 创建bitset对象时,必须要指定容器的大小.bitset对象的大小一经定义,就不能修改了.下面这条语句就定义了bitset对

C++ Primer 学习笔记_23_标准模板库_stack.

C++ Primer 学习笔记_11_标准模板库_stack.queue队列容器与priority_queue优先队列容器 1.stack堆栈 stack堆栈是一个后进先出(Last In First Out,LIFO)的线性表,插入和删除元素都只能在表的一端进行.插入元素的一端称为栈顶,而另一端称为栈底.插入元素叫入栈(Push),删除元素叫出栈(Pop).下图是堆栈示意图 堆栈只提供入栈,出栈,栈顶元素访问和判断是否为空等几种方法.采用push()方法将元素入栈:采用pop()方法出栈:采用

[学习笔记] Python标准库简明教程 [转]

1 操作系统接口 os 模块提供了一系列与系统交互的模块: >>> os.getcwd() # Return the current working directory '/home/minix/Documents/Note/Programming/python/lib1' >>> os.chdir('~/python') # Change current working directory Traceback (most recent call last): File

[学习笔记] Python标准库的学习准备 [转]

Python标准库是Python强大的动力所在,我们已经在前文中有所介绍.由于标准库所涉及的应用很广,所以需要学习一定的背景知识. 硬件原理 这一部份需要了解内存,CPU,磁盘存储以及IO的功能和性能,了解计算机工作的流程,了解指令的概念.这些内容基础而重要. Python标准库的一部份是为了提高系统的性能(比如mmap),所以有必要了解基本的计算机各个组成部分的性能. 操作系统 在了解操作系统时,下面是重点: 1) 操作系统的进程管理,比如什么是UID, PID, daemon 2) 进程之间

APUE学习笔记:第四章 文件和目录

4.1 引言 本章将描述文件的特征和文件的性质 4.2 stat.fstat和lstat函数 #include<sys/stat.h> int stat(const char *restrict pathname,struct stat *restrict buf); int fstat(int filedes,struct stat *buf) int lstat(const char *restrict pathname,struct stat *restrict buf); 三个函数的返