读书笔记-APUE第三版-(5)标准IO库

ISO C标准I/O库使用流的概念读写文件。流是对数据传输的抽象,可以把流理解为从起点到终点间的字节序列。

标准I/O库通过维护进程空间内的缓冲区,减少read/write系统调用次数来提高I/O效率。之前介绍的Unbuffered I/O和文件描述符fd打交道,标准I/O则使用FILE指针。

typedef struct{
    short level;/*缓冲区满程度*/
    unsigned flags;/*文件打开状态标志*/
    char fd;/*文件描述符*/
    unsigned char hold;/*若无缓冲区不读取*/
    short bsize; /*缓冲区大小*/
    unsigned char *buffer; /*缓冲区位置*/
    unsigned ar *curp; /*当前读写位置*/
    unsigned istemp; /*临时文件指示*/
    short token; /*用作无效检测*/
}FILE;

缓冲区

在打开文件时,标准I/O库负责自动分配缓冲区,还可以通过setbuf/setvbuf函数显式设置缓冲区类型、大小甚至关闭缓冲区。

  1. Fully buffered(全缓冲):通常情况下,硬盘上的文件读写操作都使用全缓冲,当缓冲区满的时候才触发flush操作。
  2. Line buffered(行缓冲):行缓冲一般用于终端下的标准输入/输出操作,遇到换行符或者缓冲区满时都会发生I/O操作。(注:当标准I/O库不使用缓冲或者使用行缓冲需要从内核读取数据时,行输出缓冲会被flush)。
  3. Unbuffered(不缓冲):标准错误输出不使用缓冲。

打开/关闭文件

  1. 打开文件:FILE *fopen(const char *restrict pathname, const char *restricttype);打开类型如下:
  2. 三个预定义的文件流指针被自动打开,分别是stdin标准输入、stdout标准输出和stderr标准错误流。
  3. 关闭文件:int fclose(FILE *fp);所有缓冲输出数据被flush,缓冲输入数据被丢弃。进程正常退出时,所有文件流被自动关闭

读写操作

字符读写

#include"apue.h"
int main(void)
{
    int c;
    while ((c = getc(stdin)) != EOF)
        if (putc(c, stdout) == EOF)
            err_sys("output error");
    if (ferror(stdin))
        err_sys("input error");
    exit(0);
}

读取函数包括getc(通常为宏)/fgetc(不能是宏,只能是函数)/getchar(从标准输入流读取),它们都返回int整数,从unsignedchar转换而来,这样正常返回值都是正数,可以和EOF(典型值为-1)区分出来。

行读写

#include"apue.h"
int main(void)
{
    char buf[MAXLINE];
    while (fgets(buf, MAXLINE, stdin) != NULL)
        if (fputs(buf, stdout) == EOF)
            err_sys("output error");
    if (ferror(stdin))
        err_sys("input error");
    exit(0);
}

使用fgets/gets/fputs/puts要注意以下问题:缓冲区溢出,是否自动添加\0和\n等。

二进制读写

fread和fwrite函数用于读写二进制数据。要注意的是,由于字节对齐、字节顺序、编译器、计算机体系结构差异,二进制读写兼容性比较差。

struct {
    short count;
    long total;
    char name[NAMESIZE];
} item;
if(fwrite(&item, sizeof(item), 1, fp) != 1)
    err_sys("fwrite error");

效率对比

  1. 标准I/O的User CPU时间较高,因为相比第一行read/write操作BufferSize使用4096 ,标准I/O的while循环次数要多得多。
  2. 标准I/O的System CPU时间接近最优化状态,可见标准I/O会使用合适的缓冲区大小。
  3. 最后一行每读写一个字节都进行系统调用,所以性能最差

其他重要函数

  1. 文件流定位:ftell(返回long)/ftello(返回off_t)/fseek/fseeko/rewind/fgetpos/fsetpos,后两个是ISO C标准中定义的,可以在非UNIX系统中使用
  2. 格式化:printf家族:printf(标准输出)/fprintf(输出到文件)/sprintf(输出到字符数组缓冲区)/snprintf(指定缓冲区大小避免溢出)。相对应的是scanf家族。
  3. 临时文件:tmpnam(返回唯一路径)/tmpfile(创建临时文件,关闭后被自动删除)/mkdtemp/mkstemp(能指定临时文件名模板)。
  4. 内存流:fmemopen,把某段内存当做FILE流返回,然后进行I/O操作,一般用于创建字符串

读书笔记-APUE第三版-(5)标准IO库,布布扣,bubuko.com

时间: 2024-12-05 02:18:20

读书笔记-APUE第三版-(5)标准IO库的相关文章

读书笔记-APUE第三版-(7)进程环境

本章关注单进程运行环境:启动&终止.参数传递和内存布局等. 进程启动终止 如图所示: 启动:内核通过exec函数执行程序,在main函数运行之前,会调用启动例程(start-up routine),取得命令行参数和环境变量.可以把启动例程理解为exit(main(argc,argv)). 终止:五种正常终止方式(从main方法返回/exit/_exit/最后一个线程返回/最后一个线程退出):三种异常终止方式(abort/接收到信号/最后一个线程接收到取消请求). exit与_exit关系:exi

读书笔记-APUE第三版-(8)进程控制

进程ID 每一个进程都有一个唯一的进程ID.几个特殊进程: 0号进程是内核进程,一般是调度进程swapper. 1号进程init,是用户进程(以root权限执行/sbin/init),负责初始化. 几个重要函数:getpid(进程ID)/getppid(父进程ID)/getuid(进程真有用户ID)/geteuid(进程有效用户ID)/getgid(进程真有用户组ID)/getegid(进程有效用户组ID). fork/exec/wait例程 fork家族函数用于创建子进程(父子进程关系下节详细

读书笔记-APUE第三版-(6)系统数据文件和信息

常见系统数据文件 下表列出了常见的系统数据文件及其查找函数. 以/etc/passwd文件为例,读取数据的程序基本框架如下: void get_pw_entry() { struct passwd *ptr; setpwent(); while ((ptr = getpwent()) != 0) { -- } endpwent(); return ptr; } 每个数据文件都提供了一个get方法返回文件下一个记录项. set方法充值当前位置到文件开始处. end方法关闭数据文件. 表格中的get

读书笔记-APUE第三版-(9)进程关系

登录过程 终端登录 init从/etc/ttys中读取终端信息,对每个允许登录的终端,都fork子进程,并执行getty.getty打开终端设备,执行login: execle("/bin/login,"login", "-p", username, (char *)0, envp) login进行用户名密码验证,同时还会进行切换到用户主目录/修改终端设备属主&读写权限/创建进程组/setuid等动作,然后运行login shell. execl(

《APUE》-第五章标准IO库

大多数UNIX应用程序都使用I/O库,本章说明了该库所包含的所有函数,以及某些实现细节和效率方面的考虑.同时需要重点关注标准I/O使用了缓冲的技术,但同时也是因为它的出现,产生了很多细节上的问题. 流和FILE对象 unix系统调用的函数都是针对文件描述符操作的.而标准I/O库,它们的操作则是围绕流进行的.当用标准I/O库打开或创建一个文件时,使一个流与一个文件相关联. 关于流定向的问题,当一个流刚被创建时,它并没有定向,我们可以在未定向的流上使用一个多字节I/O函数或者单字节的函数. #inc

【字源大挪移—读书笔记】 第三部分:字尾

[字源大挪移—读书笔记] 第三部分:字尾 [3 字尾:[3.1]名词字尾.[3.2]形容词字尾.[3.3]副词字尾.[3.4]动词字尾 [3.1]名词字尾(Noun) [3.1.1]表示[人]的字尾 -ain -aire -an -ian -ean -ese -ant -ent -ary -ate -ee {[备注]:和-er相反,表示"被……的人":} -eer -er -or -ar -ier -eur -ician -ist -ite -ive -man -on -ster -y

C++ Primer 读书笔记: 第8章 标准IO库

第8章 标准IO库 8.1 面向对象的标准库 1. IO类型在三个独立的头文件中定义:iostream定义读写控制窗口的类型,fstream定义读写已命名文件的类型,而sstream所定义的类型则用于读写存储在内存中的string对象.在fstream和sstream里定义的美中类型都是从iostream头文件中定义的相关类型派生而来. 2. 流对象不能复制,因此不能存储在vector容器中 3. 形参或返回类型也不能为流类型.如果需要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用.

[APUE]标准IO库(下)

一.标准IO的效率 对比以下四个程序的用户CPU.系统CPU与时钟时间对比 程序1:系统IO 程序2:标准IO getc版本 程序3:标准IO fgets版本 结果: [注:该表截取自APUE,上表中"表3-1中的最佳时间即<程序1>","表3-1中的单字节时间指的是<程序1>中BUFSIZE为1时运行时间结果",fgetc/fputc版本程序这里没放出] 对于三个标准IO版本的每一个其用户CPU时间都大于最佳read版本,因为每次读一个字符

嵌入式 Linux系统编程(三)——标准IO库

嵌入式 Linux系统编程(三)--标准IO库 与文件IO函数相类似,标准IO库中提供的是fopen.fclose.fread.fwrite等面向流对象的IO函数,这些函数在实现时本身就要调用linux的文件IO这些系统调用. 一.标准IO库函数的缓冲机制 由于IO设备的访问速度与CPU的速度相差好几个数量级,为了协调IO设备与CPU的速度的不匹配,对于块设备,内核使用了页高速缓存,即数据会先被拷贝到操作系统内核的页缓存区中,然后才会从操作系统内核的缓存区拷贝到应用程序的地址空间. 当应用程序尝