UNIX高级编程总结-----标准I/O库 (一 流、缓冲、打开流、读写流)

一、流 和 FILE对象

        之前在文件I/O中提到的函数,都是围绕文件描述符的,当打开一个文件时,返回的是一个文件描述符,然后对该文件描述符进行后续的I/O操作。而对于标准I/O库,他们的操作是围绕着 流 进行的。当用标准I/O库打开或创建一个文件时,我们就使一个流与一个文件相关联。

        在标准IO流中预定义了3个文件指针,stdin(标准输入)、stdout(标准输出)、stderr(标准错误)。这三个文件指针都定义<stdio.h>中。

        对于ASCII字符集,一个字符用一个字节来表示。对于国际字符集而言,一个字符可用多个字符集来表示。标准I/O文件流可用于单字节或多字节(俗称"宽")字符集

        流的定向,决定了所读所写的字符是单字节的还是多字节的。当一个流刚被创建出来时,是没有定向的,如果在一个没有定向的流上使用一个多字节的I/O函数,则将该流设置为宽定向,具体多宽由使用的多字节IO函数定。有两个函数可以改变流的定向:

(1) fwide函数

#include<stdio.h>

#include<wchar.h>

int fwide(FILE *fp, int mode);

                   返回值:若流是宽定向的,返回正值;若流是字节定向的,返回负值;若流是为定向的,返回0 

 

        注意:

        fwide并不改变以定向流的定向。还应注意的是,fwide无出错返回。试想一下如果流是无效的会发生什么呢?我们唯一依靠的就是fwide前先清除errno,从fwide返回时检查errno的值。

(2) freopen函数

        该函数的解释,可见   三、打开流

二、缓 冲

1、标准IO库提供缓冲的目的是,尽可能少的使用read和write调用次数。标准IO的底层实现是运用了read和write,通过缓冲区将要写入或者读出的数据先放到缓冲区中,然后达到一定的条件后(比如:缓冲区满、遇见换行符 等等)去调用一次read或是write。

2、标准的IO提供了三种类型的缓冲

        (1)全缓冲:

        在填满标准的IO缓冲区后才进行实际的IO操作。对于驻留在磁盘上的文件通常是有标准IO库实施全缓冲的。在一个流上执行第一次操作时,相关的标准IO函数通常是调用malloc去获得所需的缓冲区。

        该类型的缓冲区会在 缓冲区填满时 以及  调用fflush()冲刷流时执行一次写操作。

        (2)行缓冲:

        在遇到换行符时,执行一次IO操作。对于行缓冲有两个限制,

        第一,因为标准IO库用来收集每一行的缓冲区的长度是固定的,所以只要填满了缓冲区,那么即使没有写一个换行符也执行一次IO操作。

        第二,任何时候只要通过标准IO库要求从一个不带缓冲的流,或者是一个行缓冲的流(它从内核请求需要的数据)得到输入数据,那么就会冲洗所有的行缓冲输出流。对于行缓冲的流后面的括号中的说明,着重解释一下:

        从不带缓冲的流中输入需要从内核中获取数据。

        从行缓冲的流中得到输入数据,所需的数据可能还在缓冲区中,不需要从内核中读数据。

        (3)不带缓冲:

        不对字符进行缓冲存储。比如:stderr

        ISO C中要求缓冲有一下几项特征:

        a、当且仅当标准输入和标准输出,并不指向交互式设备时,他们才是全缓冲。当指向交互设备时,是行缓冲还是无缓冲都视情况而定,很多系统在指向交互设备后,默认标准错误无缓冲。

        b、标准错误永远不会是全缓冲。

 

        对任意一个给定的流,若不喜欢他的默认缓冲类型,可以通过下列函数去进行修改缓冲类型。

#include<stdio.h>

void setbuf(FILE *restrict fp, char *restrict buf);

void setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);

                   返回值:成功,返回0;失败,返回,非0 

        void setbuf(FILE *restrict fp, char *restrict buf);

        可以使用 setbuf 去打开或关闭缓冲机制,参数buf不需指向一个长度为 BUFSIZ 的缓冲区,设置之后该流的缓冲区为全缓冲。如果要关闭缓冲机制,则将 buf 为NULL。

#include <stdio.h>
char outbuf[50];
#if 0
int main(void)
{
    /* 将outbuf与stdout输出流相连接 */
    setbuf(stdout,outbuf);
    /* 向stdout中放入一些字符串 */
    puts("This is a test of buffered output.");
    puts("This output will go into outbuf");
    puts("and won't appear until the buffer");
    puts("fills up or we flush the stream.\n");
    /* 以下是outbuf中的内容 */
//    puts(outbuf);
    /*刷新流*/
//    fflush(stdout);
    return 0;
}
#else
 
#include<stdio.h>
#include<stdlib.h>
//char buf[6];
int main()
{
    // static char buf[6];
    setbuf(stdout,malloc(100));
    int c;
 
    int i = 0;
    while((c=getchar())!=EOF && getchar())
    {
        putchar(c);
#if 1
        printf("hello\n");
        i++;
        if(i>5)  
        {  
            return 0;  
        }  
#endif  
    }  
    return 0;  

#endif     

       void setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);

       参数:stream :指向流的指针 ;
             buf       : 期望缓冲区的地址;
             type     : 期望缓冲区的类型:
                    _IOFBF(全缓冲):当缓冲区为空时,从流读入数据。或者当缓冲区满时,向流写入数 据。
                    _IOLBF(行缓冲):每次从流中读入一行数据或向流中写入一行数据。
                    _IONBF(无缓冲):直接从流中读入数据或直接向流中写入数据,而没有缓冲区。
             size     : 缓冲区内字节的数量。
  注意:意思是这个函数应该在打开流后,立即调用,在任何对该流做输入输出前
 

        下面是这两个函数,参数设置之后其得到的缓冲类型的表:

补充说明一个常见C语言关键字:

        restrict

三、打开流 

        

#include<stdio.h>

FILE* fopen(const char *restrict pathname, char *restrict type);

FILE* freopen(const char *restrict pathname, char *restrict type, FILE* restrict fp);

FILE* fdopen(int fd, const char *type);

                   返回值:成功,返回文件指针;失败,返回NULL 

    (1) fopen 打开路径执行一个文件

    (2) freopen 在一个制定的流(三参)上打开一个文件(一参),如果该流打开了,那就先关闭之前的流,然后再打开新的文件。如果该流已定向,则 freopen 清除该定向。通常该函数将一个指定的文件打开为一个预定义的流,标准输入、标准输出、标准错误。 

    (3) fdopen 这个函数比较有用。将一个文件描述符(open,dup,管道、socket等)与一个标准IO中的流相结合。此函数用于创建管道和网络通信通道函数返回的描述符。因为这些特殊的文件描述符不能用标准IO函数fopen打开,所以必须使用该函数将其文件描述符与流相结合。

    这三个都有一个标准IO流的参数,其解释如下:

注意1:在 UNIX 环境下,UNIX内核对二进制文件 和 文本文件不做区分,故 b 选项没有意义。

注意2:还有以下在使用fdopen时的注意事项:

注意3:还有注意的一点就是,用 w 或是 a 创建一个新文件时,无发说明该文件的访问权限位。文件IO中,open和creat都能做到。如果要用标准IO用权限位集来创建文件时,必须使用umask函数。在这里需要插入一个文件和目录的知识点umask函数:

include<sys/stat.h>

mode_t umask(mode_t cmask); 

                 返回值:之前的文件模式创建屏蔽字 

    在Linux中设置umask值以及umask函数

注意4: 流引用的是终端设备,该流属于行缓冲;按系统默认情况下,流被打开是全缓冲。

 

四、读写流

        在打开流之后,有三种不同类型的非格式化IO进行读写操作:

        (1) 每次一个字符的IO。一次的读或写一个字符,如果流带缓冲,则标准IO函数处理所有的缓冲。

        (2) 每次一行的IO。读写以换行符结尾,主要函数有 fputs 和 fgets .

        (3) 直接IO。每次的IO操作读或写某种数量的对象,而每个对象具有指定的长度。常用于从二进制文件中每次读写一个结构等,主要的函数 fread 和 fwrite。

    1、用于一次只读一个字符的函数(总共三个函数)

include<stdio.h>

int getc(FILE *fp);

int fgetc(FILE *fp);

int getchar(void); 

                 返回值:成功返回下一个字符;

                                若文件已到达文件尾端或出错,返回EOF

        函数 getchar  等同于  getc(stdin); getc 可被定义为宏,而fgetc不能实现为宏,其解释引用书中原文:

注意:

       

        在这三个函数中,他们无论 出错 还是 到文件尾端其返回的都是EOF,为了区分这两种情况,引入了两个函数:

include<stdio.h>

int ferror(FILE *fp);

int feof(FILE *fp); 

                 返回值:条件为真,返回非0;条件为假,返回0

void clearerr(FILE *fp);

他的区分原理是,如下:

 

        从流中读取的数据,可以通过 ungetc 将字符再压回去;

#include<stdio.h>

int ungetc(int c,FILE* fp);

                               返回值:若成功,返回c;若出错,返回EOF

 ungetc 该函数实现并不是在底层文件或是设备上执行的,而是在标准IO的缓冲区中操作的。以下是书中全部的解释:

      以上是介绍了每次单个字符的读操作,以下是写操作,也是三个函数

include<stdio.h>

int putc(int c, FILE *fp);

int fputc(int c, FILE *fp);

int putchar(int c); 

                 返回值:成功返回c;若出错,返回EOF

 putchar(c)  等同于  putc(c, stdout)  ;putc可被实现为宏,而 fputc 不能实现为宏。

 

 

文章引用:setbuf 和setvbuf 简单介绍

下一篇

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
起步 jusr 01.txtj 关于本手册 jusr 02.txtj Vim第一步 jusr 03.txtj 移动 jusr 04.txtj 小幅改动 jusr 05.txtj 定制你的Vim jusr 06.txtj 使用语法高亮 jusr 07.txtj 编辑多个文件 jusr 08.txtj 分隔窗口 jusr 09.txtj 使用GUI jusr 10.txtj 大刀阔斧 jusr 11.txtj 灾难恢复 jusr 12.txtj 奇技淫巧 高效编辑 jusr 20.txtj 加速冒号命令 jusr 21.txtj 进退之间 jusr 22.txtj 查找要编辑的文件 jusr 23.txtj 非文本文件 jusr 24.txtj 快速键入 jusr 25.txtj 编辑格式化文本 jusr 26.txtj 重复重复, 再重复 jusr 27.txtj 搜索命令和模式 jusr 28.txtj 折行 8 9 第00章目录 jusr 29.txtj 之于程序 jusr 30.txtj 程序的编辑 jusr 31.txtj 探索GUI 打造Vim jusr 40.txtj 定义新命令 jusr 41.txtj Vim脚本 jusr 42.txtj 增加新菜单 jusr 43.txtj 文件类型 jusr 44.txtj 自定义语法高亮文件 jusr 45.txtj 选择语言 运转Vim jusr 90.txtj 安装Vim 可以在下面的地址中找到以单个文件组织的可打印版的HTML或PDF格 式用户手册: http://vimdoc.sf.net 起步 请从头至尾细读本章, 本章讲述Vim的基本命令. jusr 01.txtj 关于本手册 j01.1j 两套帮助 j01.2j 关于安装 j01.3j 使用Vim教程 j01.4j 版权 jusr 02.txtj Vim第一步 j02.1j 首次运行Vim j02.2j 插入文本 9 10 第00章目录 j02.3j 移动光标 j02.4j 删除字符 j02.5j 撤消与重做 j02.6j 其它编辑命令 j02.7j 退出 j02.8j 求助 jusr 03.txtj 移动 j03.1j 以Word为单位的光标移动 j03.2j 将光标移到行首或行尾 j03.3j 将光标移动到指定的字符上 j03.4j 将光标移动到匹配的括号上 j03.5j 将光标移动到指定的行上 j03.6j 告诉你当前位置 j03.7j 滚屏 j03.8j 简单的搜索 j03.9j 简单的模式搜索 j03.10j 使用标记 jusr 04.txtj 小幅改动 j04.1j 操作符命令和位移 j04.2j 改变文本 j04.3j 重复改动 j04.4j Visual模式 j04.5j 移动文本 j04.6j 复制文本 j04.7j 使用剪贴板 j04.8j 文本对象 j04.9j 替换模式 j04.10j 结论 jusr 05.txtj 定制你的Vim j05.1j vimrc文件 j05.2j vimrc示例 j05.3j 简单的映射 j05.4j 增加一个plugin j05.5j 增加一个帮助文件 j05.6j 选项设置窗口 j05.7j 常用选项 10 11 第00章目录 jusr 06.txtj 使用语法高亮 j06.1j 打开色彩 j06.2j 没有色彩或色彩错误? j06.3j 不同的颜色 j06.4j 有色或无色 j06.5j 彩色打印 j06.6j 进一步的学习 jusr 07.txtj 编辑多个文件 j07.1j 编辑另一个文件 j07.2j 文件列表 j07.3j 切换到另一文件 j07.4j 备份 j07.5j 在文件间复制粘贴 j07.6j 查看文件 j07.7j 更改文件名 jusr 08.txtj 分隔窗口 j08.1j 分隔一个窗口 j08.2j 为另一个文件分隔出一个窗口 j08.3j 窗口大小 j08.4j 垂直分隔 j08.5j 移动窗口 j08.6j 针对所有窗口操作的命令 j08.7j 使用vimdiff查看不同 j08.8j 其它 jusr 09.txtj 使用GUI j09.1j GUI的各部分 j09.2j 使用鼠标 j09.3j 剪贴板 j09.4j 选择模式 jusr 10.txtj 大刀阔斧 j10.1j 命令的记录与回放 j10.2j 替换 11 12 第00章目录 j10.3j 使用作用范围 j10.4j 全局命令 j10.5j 可视块模式 j10.6j 读写文件的部分内容 j10.7j 格式化文本 j10.8j 改变大小写 j10.9j 使用外部程序 jusr 11.txtj 灾难恢复 j11.1j 基本方法 j11.2j 交换文件在哪? j11.3j 是不是死机了? j11.4j 进一步的学习 jusr 12.txtj 奇技淫巧 j12.1j 替换一个word j12.2j 将"Last, First"改为"First Last" j12.3j 排序 j12.4j 反转行序 j12.5j 统计字数 j12.6j 查找帮助页1 j12.7j 消除多余空格 j12.8j 查找一个word在何处被引用 高效编辑 此类主题可以独立阅读 jusr 20.txtj 加速冒号命令 j20.1j 命令行编辑 j20.2j 命令行缩写 j20.3j 命令行补齐 j20.4j 命令行历史记录 j20.5j 命令行窗口 1译: 仅对Unix类系统有意义 12 13 第00章目录 jusr 21.txtj 进退之道 j21.1j 挂起与恢复 j21.2j 执行shell命令 j21.3j 记住相关信息: viminfo j21.4j 会话 j21.5j 视图 j21.6j 模式行 jusr 22.txtj 查找要编辑的文件 j22.1j 文件浏览器 j22.2j 当前目录 j22.3j 查找一个文件 j22.4j 缓冲区列表 jusr 23.txtj 非文本文件 j23.1j DOS, Mac 和Unix格式的文件 j23.2j 来自因特网的文件 j23.3j 加密文件 j23.4j 二进制文件 j23.5j 压缩文件 jusr 24.txtj 快速键入 j24.1j 校正 j24.2j 显示匹配字符 j24.3j 自动补全 j24.4j 重复录入 j24.5j 从其它行复制 j24.6j 插入一个寄存器的内容 j24.7j 缩写 j24.8j 键入特殊字符 j24.9j 键入连字符 j24.10j Normal模式命令 jusr 25.txtj 编辑格式化文本 j25.1j 段行 j25.2j 文本对齐 13 14 第00章目录 j25.3j 缩进和制表符 j25.4j 处理长行 j25.5j 编辑表格 jusr 26.txtj 重复重复, 再重复 j26.1j Visual模式的重复 j26.2j 加与减 j26.3j 对多个文件做同样的改动 j26.4j 在一个shell脚本中使用Vim jusr 27.txtj 搜索命令和模式 j27.1j 忽略大小写 j27.2j 绕回文件头尾 j27.3j 偏移 j27.4j 多次匹配 j27.5j 多选一 j27.6j 字符范围 j27.7j 字符分类 j27.8j 匹配一个断行 j27.9j 例子 jusr 28.txtj 折行 j28.1j 什么是折行? j28.2j 手工折行 j28.3j 使用折行 j28.4j 保存和恢复折行 j28.5j 根据缩进的折行 j28.6j 根据标记的折行 j28.7j 根据语法的折行 j28.8j 根据表达式折行 j28.9j 折叠未有改变的行 j28.10j 使用何种折行方法? jusr 29.txtj 之于程序 j29.1j 使用tags j29.2j 预览窗口 14 15 第00章目录 j29.3j 在程序中移动 j29.4j 查找全局标识符 j29.5j 查找局部标识符 jusr 30.txtj 程序的编辑 j30.1j 编译 j30.2j C程序的缩进 j30.3j 自动缩进 j30.4j 其它语言的缩进 j30.5j 跳格键与空格 j30.6j 注释的格式化 jusr 31.txtj 探索GUI j31.1j 文件浏览器 j31.2j 确认 j31.3j 菜单命令的快捷键 j31.4j Vim的窗口位置和大小 j31.5j 其它 调节Vim 让Vim如你所愿地工作 jusr 40.txtj 定义新命令 j40.1j 键映射 j40.2j 自定义冒号命令 j40.3j 自动命令 jusr 41.txtj Vim脚本 j41.1j 介绍 j41.2j 变量 j41.3j 表达式 j41.4j 条件语句 j41.5j 执行一个表达式 15 16 第00章目录 j41.6j 使用函数 j41.7j 函数定义 j41.8j 注意事项 j41.9j 定制一个plugin j41.10j 定制一个文件类型相关的plugin j41.11j 定制一个编译相关的plugin jusr 42.txtj 增加新菜单 j42.1j 介绍 j42.2j 菜单操作命令 j42.3j 其它 j42.4j 工具栏和弹出式菜单 jusr 43.txtj 文件类型 j43.1j 文件类型的插件 j43.2j 添加一种文件类型 jusr 44.txtj 自定义语法高亮文件 j44.1j 基本的语法命令 j44.2j 关键字 j44.3j 匹配 j44.4j 区域 j44.5j 嵌套 j44.6j 后续组 j44.7j 其它参数 j44.8j 聚簇 j44.9j 包含另一个语法文件 j44.10j 同步 j44.11j 安装一个语法文件 j44.12j 可移植语法文件的布局要求 jusr 45.txtj 选择语言 j45.1j 用于消息的语言 j45.2j 用于菜单的语言 j45.3j 使用另一种编码方法 j45.4j 编辑另类编码方案的文件 j45.5j 输入 16 17 第00章目录 运转Vim Vimming之前. jusr 90.txtj 安装Vim j90.1j Unix j90.2j MS-Windows j90.3j 升级 j90.4j 常见问题 j90.5j 卸载Vim

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值