六、读和写流

  一旦打开了流,则可在3种不同类型的非格式化I/O中进行选择,对其进行读、写操作:1)每次一个字符的I/O,一次读或写一个字符,如果刘时代缓冲的,则标准I/O函数处理所有缓冲;2)每次一行的I/O。如果想要一次读或写一行,则使用fgets和fputs。每行都以一个换行符终止。当调用fgets时,应说明能处理的最大行长。3)直接I/O(这个术语来自ISO C标准,有时也被称为二进制I/O,一次一个对象的I/O、面向记录的I/O或面向结构的I/O)。fread和fwrite函数支持这种类型的I/O。每次I/O操作读或写某种数据的对象,而每个对象具有指定的长度。这两个函数常用于从二进制文件每次读或写一个结构。

1.输入函数

#include <stdio.h>
int get(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
//若成功,返回下一个字符;若已经到达文件尾端或出错,返回EOF

  函数getchar等同于fgetc(stdin)。前两个函数的区别是getc可被实现为宏,而fgetc不能被事先未宏,这意味着以下几点区别:1)getc的参数不应当是具有副作用的表达式,因为他可能会被计算多次;2)因为fgetc一定是个函数,所以可以得到其地址。这就允许将fgetc的地址作为一个参数传送给另一个函数;3)调用fgetc所需时间很可能比调用getc要长,因为调用函数所需的时间通常长于调用宏。

  需要注意的是不管是出错还是达到文件的尾端,这三个函数都返回同样的值,为了区分这两种不同的情况,必须调用ferror或feof,这是因为大多数实现中,为每个流在FILE对象中维护了两个标志:出错标志;文件结束标志。clearerr可以清除这两个标志。

#include <stdio.h>
int gerror(FILE *fp);
int feof(FILE *fp);
//若条件为真,返回非0;否则,返回0 void clearerr(FILE *fp);

  从流中读取数据以后,可以调用ungetc将字符再压送回流中。压送回流中的字符以后又可从流中读出,但读出字符的顺序与压送回的顺序相反。不能回送EOF,。但是当已经到达文件尾端时,仍可以回送一个字符。下次读将返回该自负,再读则返回EOF。之所以能这样做的原因是:一次成功的ungetc调用会清除该流的文件结束标志。用ungetc压送回字符时,并没有将他们写到底层文件中或设备上,知识将它们写会标准I/O库的流缓冲区中。

#include <stdio.h>
int ungetc(int c, FILE *fp);
//若成功,返回c;若出错,返回EOF

2、输出函数
  对应于上面所述的每个输入函数都有一个输出函数:

#include <stdio.h>
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);

七、每次一行I/O

#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *restrict buf);

  对于fgets,必须指定缓冲的长度n,次函数一直读到下一个换行符为止,但是不超过n-1个字符,读入的字符被送入缓冲去。该缓冲区以null字节结尾。如该行包括最后一个换行符的字符数超过n-1,则只返回一个不完整的行,但是,缓冲区总是yinull字节结尾。对fgets的下一次调用会继续该执行。gets不推荐使用,可能造成缓冲区溢出。

#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);
//若成功,返回非负值;若出错,返回EOF

  fputs讲一个以null字节终止的字符串写到指定的流,尾端的终止符null不写出。puts并不像它所对应的gets那样不安全,但是我们还是应避免使用它,以免需要记住它最后是否添加一个换行符。

八、标准I/O的效率

#include <apue.h>
#include <my_err.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();
}

5-4 用getc和putc将标准输入复制到标准输出

#include <apue.h>
#include <my_err.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();
}

5-5 用fgets和fputs将标准输入复制到标准输出

  

函数

用户cpu

系统cpu

时钟时间

程序正文字节数

图3-6最佳时间

0.05

0.29

3.18

fgets/fputs

2.27

0.30

3.49

143

getc/putc

8.45

0.29

10.33

114

fgetc/fputc

8.16

0.40

10.18

114

图3-6单字节时间

134.61

249.94

394.95

5-6 使用标准I/O例程得到的时间结果

1、系统CPU时间几乎相同,原因是因为所有这些程序对内核提出的读写请求数基本相同

2、fgets优于fgetc,是因为fgets底层拷贝使用memccpy,并且减少了函数调用次数

3、fgetc和getc没有明显区别的原因是getc是宏简单地扩充为函数调用

4、fgetc、fputc大大优于单字节时间是因为虽然函数调用次数差不多,但是fgetc/fputc是普通的函数调用,而单字节是系统调用read。系统调用花费的时间大大超过普通函数调用。

九、二进制I/O

  当我们一次需要处理一个完整的结构,我们就需要二进制I/O。典型的应用场景如读写一个二进制数组;读或写一个结构。

#include <stdio.h>
size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
//两个函数的返回值:读或写的对象数

  fread和fwrite返回读或写的对象数。对于读、如果出错或到达文件尾端,则此数字可以少于nobj、在这种情况,应调用ferror或feof以判断究竟是哪一种情况。对于写,如果返回值少于所要求的nobj,则出错。使用二进制I/O还需要注意两个问题:1)在一个结构中,同意成员的偏移量可能随编译程序和系统的不同而不同;2)用来储存多字节整数和复电纸的二进制格式在不同的系统结构间也可能不同。

APUE(5)---标准I/O库 (2)的更多相关文章

  1. [05]APUE:标准 I/O 库

    [a] setvbuf / setbuf #include <stdio.h> int setvbuf(FILE *restrict fp, char *restrict buf, int ...

  2. APUE(5)---标准I/O库 (3)

    十.定位流 #include <stdio.h> long ftell(FILE *fp); //若成功,返回当前文件位置指示:若出错,返回-1L int fseek(FILE *fp, ...

  3. APUE(5)---标准I/O库 (1)

    一.引言 标准I/O库不仅是UNIX,许多i其他操作系统都实现了标准I/O库,所以这个库由ISO C标准说明.标准I/O库处理很多细节,如缓冲区分配,以及优化的块长度执行I/O等.这使得它便于用户使用 ...

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

    1.流与FILE对象 unix I/O系统调用都是针对文件描述符的 标准C的I/O函数都是针对流(文件指针)的,我们使用一个流与一个文件相关联   2.缓冲 标准I/O库提供缓冲的目的就是尽可能减少r ...

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

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

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

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

  7. (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  8. 标准I/O库之临时文件

    ISO C标准I/O库提供了两个函数以帮助创建临时文件. #include <stdio.h> char *tmpnam( char *ptr ); 返回值:指向唯一路径名的指针 FILE ...

  9. 标准I/O库之标准I/O的效率

    程序清单5-1 用getc和putc将标准输入复制到标准输出 #include "apue.h" int main( void ) { int c; while(( c = get ...

随机推荐

  1. Android利用百度云来识别身份证及各种证件的信息

    上一篇中我已经介绍过了ocr,及google出来的tess-two的使用. 接下来我来介绍一个更方便的身份证识别系统,当然它本身也是利用ocr来识别文字的,不过它处理的更好,可以为我们提供更快,更准确 ...

  2. 线程之 CPthon中的GIL与Lock的分析与解决办法

    Cpython 中的GIL锁介绍 1. 前戏 In CPython, the global interpreter lock, or GIL, is a mutex that prevents mul ...

  3. Julia - 字符串判断函数

    isascii() 判断是否是 ascii 码,返回 Bool 值 julia> isascii('a') true julia> isascii('α') false julia> ...

  4. 广义线性模型(Generalized Linear Models)

    在线性回归问题中,我们假设,而在分类问题中,我们假设,它们都是广义线性模型的例子,而广义线性模型就是把自变量的线性预测函数当作因变量的估计值.很多模型都是基于广义线性模型的,例如,传统的线性回归模型, ...

  5. Redis常用类型数据操作

    sortedset: 添加: zadd key score1 member1 score2 member2...  zad mysort 90 laosong 100 zhangsan 获得:zsco ...

  6. 201671010140. 2016-2017-2 《Java程序设计》java学习第十五周

    java学习第十五周 Java的GUI界面设计,框架以及主要部件填充,归置,布局管理,在第十一章和第十二章进行了系统的学习,在这两章的知识奠基下,可以简单的构造一个GUI用户界面,在两周的学习后,可以 ...

  7. C#使用NPOI导出excel设置单元格背景颜色

    ICellStyle cellStyle = workbook.CreateCellStyle(); cellStyle.FillPattern = FillPattern.SolidForegrou ...

  8. 【UVA11419 训练指南】我是SAM 【二分图最小覆盖,最小割】

    题意 给出一个R*C大小的网格,网格上面放了一些目标.可以在网格外发射子弹,子弹会沿着垂直或者水平方向飞行,并且打掉飞行路径上的所有目标.你的任务是计算最少需要多少子弹,各从哪些位置发射,才能把所有目 ...

  9. Comet OJ - Contest #2 D 枚举重心

    题面 思路: 函数f相当于是求一个点集f的直径,有一个性质是如果这个点集有多个直径一定相交于某一个点,或者一条边的中心,所以我们暴力枚举重心,计算以某个点为重心的点集对答案的贡献. 具体实现的时候,我 ...

  10. 快速上手Runtime(四)之动态添加方法

    如果一个类方法非常多,加载类到内存的时候也比较耗费资源,可以使用动态给某个类,添加方法解决.做到优化内存,节省资源的效果. // // Person.m // ResolveInstanceMetho ...