1.流和FILE对象
  对于国际字符集,一个字符可以由一个以上的字节来表示。标准I/O文件流可以用来操作单字节和多字节(宽,wide)字符集。一个流的方向(orientation)决定了字符是以单字节还是多字节的方式读取,当一个流被创建时,它没有方向。如一个多字节I/O函数(见<wchar.h>)用在了没有方向的流上,那么流的方向会设为面向宽字符的。如果一个字节I/O函数用在一个没有方向的流上,那么流的方向会设为面向字节的。只有两个函数可以在设置后改变这个方向。freopen函数(简单说明)将会清除一个流的方向,而 fwide函数用来设置一个流的方向。

#include <stdio.h>
#include <wchar.h>
int fwide(FILE *fp, int mode);
//流面向宽字符返回正值、面向字节返回负值、没有方向则返回0。

根据mode参数的不同值,fwdie函数执行不同的任务:
1).如果mode参数为负值,fwide将会尝试让流面向字节;
2).如果mode参数为正值,fwide将会尝试让流面向宽字符;
3).如果mode参数为0,fwid将不会设置方向,而是返回一个表示流的方向的值。
注意fwide不会改变一个已经有方向的流的方向。同样注意它不会返回错误。
当打开一个流时,标准I/O函数fopen返回一个指向一个FILE对象的指针。这个对象通常是一个包含所有标准I/O库管理流所需的所有信息的结构体。

2.缓冲
三种缓冲类型:
1).全缓冲:在这种情况下,当标准I/O的缓冲被填满后,真实的I/O才会发生。在磁盘上的文件通常都被标准I/O库完全缓冲。这个被使用的缓冲通常被标准I/O库在第一次操作一个流时通过调用malloc得到.注:Stdin和stdout如果被重定位到文件上,则是完全缓冲
术语“冲洗(flush)”描述了标准I/O缓冲的写操作。一个缓冲可以被标准I/O函数自动冲洗,比如在缓冲满时,或者我们可以调用函数fflush来冲洗一个流。不幸的是,在UNIX环境里,冲洗有两个意思。在标准I/O库里,它表示缓冲的内容写出,它可能是部分填充的。

2).行缓冲:在这种情况下,标准I/O库在输入输出时碰到一个换行符时会执行I/O操作。这让我们可以一次输出单个字符(使用标准I/O的 fputc函数),因为我们知道只当我们完成了每行的写操作时真实I/O才会发生。行缓冲被典型用在终端的流上:比如标准输入、标准输出。
行缓冲伴随两个警告。第一,标准I/O库用来收集各行的缓冲区大小是固定的,所以当我们在写一个换行符之前填满这个缓冲I/O可能会发生。第二、不管何时通过标准I/O库从a、一个未缓冲流或b、(需要从内核被请求数据的)一个行缓冲流请求一个输入时,所有行缓冲输出流都会被冲洗。b情况括号内的补充条件的原因是,请求的数据可能已经在缓冲里了,这时不再需要从内核中读取数据。显然,a情况下任何从未缓冲流的输入,都会要求从内核获取数据。

3).无缓冲:标准I/O库不缓冲字符。例如,如果我们用标准I/O函数fputs写15个字符,我们会期望这15个字符尽快地输出,它很可能使用了3.8节的write函数。
标准错误流通常是无缓冲的。这是为了使任何错误消息都能尽快地显示,而不管它们是否包含一个换行符。
通过调用下面两个函数的其中一个来改变缓冲:

#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值。

3.打开流
1).下面三个函数打开一个标准I/O流

#include <stdio.h>
FILE *fopen(const char *restrict pathname, const char *restrict type);
FILE *freopen(const char *restrict pathname, const char *restrict type, FILE *restrict fp);
FILE *fdopen(int filedes, const char *type);
//成功返回文件指针,错误返回NULL。

区别:

a.fopen函数打开一个指定的文件。
b.freopen函数在一个指定的流上打开一个指定的文件,并关闭之前打开的流。如果之前的流有方向,freopen会清除它.
c.fdopen函数接受一个已有的文件描述符,它可以通过open、dup、dup2、fcntl、pipe、socket、socketpair或 accept函数得到

2).一个打开的流可以调用fclose来关闭

#include <stdio.h>
int fclose(FILE *fp);
//成功返回0,错误返回EOF

任何缓冲的输出数据都在文件关闭前被冲洗。任何可能被缓冲的输入数据都会被舍弃。如果标准I/O库之前自动开辟了一个缓冲,这个缓冲会被释放

4.读和写流
打开一个流,可以从以下三种非格式化的I/O中选择:
● 一次一字符(Character-at-a-time)I/O。我们可以一次读写一个字符,而让标准I/O函数处理所有的缓冲事宜,如果流有缓冲的话。
● 一次一行(Line-at-a-time)I/O。如果我们读一次读写一行,我们使用fgets和fputs。每行都以一个换行符终止,而且当我们调用fgets时必须指定我们能处理的最大行长度。
● 直接(Direct)I/O。这种类型的I/O通过fread和fwrite函数支持。对于每个I/O操作,我们读写一些对象,而每个对象都有一个指定的尺寸。这两个函数经常用来处理二进制文件,那里我们每次操作读写一个结构。
1).输入函数:
下面三个函数允许我们一次读一个字符

#include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
//三者成功都返回下一个字符,失败都返回EOF。

函数getchar被定义为与getc(stdin)等价。前两个函数的区别是getc可以被作为一个宏而实现,而fgetc不能作为宏实现

2).注意上面三个函数当碰到一个错误或到达文件尾时返回同一个值。为了区别这两者,我们必须调用ferror或feof

#include <stdio.h>
int ferror(FILE *fp);
int feof(FILE *fp);
//两者如果条件成立的话返回非0(真),否则返回0(假)。
void clearerr(FILE *fp);

在多数实现上,在FILE对象里为每个流维护了两个标志:

a.一个错误标志
b.一个文件结束标志
两个标志都可以调用clearerr来清除。

3).在从一个流读入后,我们可以调用ungetc来把字符放回去。

#include <stdio.h>
int ungetc(int c, FILE *fp);
//成功返回c,否则返回EOF。

放回的字符会被后续在流上的读操作以放回的相反顺序返回

4).输出函数
对应于每个之前讨论过的输入函数的输出输出有:

#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可以作为一个宏实现(将被替换为IO_putc),但fputc不能作为一个宏实现

5.每次一行I/O
1).以下两个函数提供一次一行输入功能

#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE* restrict fp);
char *gets(char *buf);
//两者成功返回buf,文件结束或错误返回NULL。

两都都指明一个把行读入的缓冲区的地址。gets函数从标准输入中读,而fgets从指定的流中读取。

2).一次一行输出由fputs和puts提供

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

函数fputs把一个null终止的字符串写入到指定的流中,末尾的null字节没有被写,puts函数在标准输出写一个空字符终止的字符串,但不会把这个空字节写出。不同的是puts接着会把一个换行符写入到标准输出

6.二进制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);
//两者都返回读或写的对象数。

这些函数有两种普遍的使用方法:

1)读写一个二进制数组。
2)读写一个结构体。

7.定位流
有三种方式来定位一个标准I/O流
1)

#include <stdio.h>
long ftell(FILE *fp);
//如果成功返回当前文件位置指示器,错误返回-1L。
int fseek(FILE *fp, long offset, int whence);
//成功返回0,否则返回非0值。
void rewind(FILE *fp);

对于一个二进制文件,一个文件的位置指示器是从文件开始的字节来衡量的.

a.ftell用于二进制文件,返回值是这个字节位置。
b.为了用fseek定位一个二进制文件,我们必须指定一个字节偏移以及这个偏移如何被解释。whence的值和前面的lseek函数里的一样:SEEK_SET表示从文件开头开始;SEEK_CUR表示从当前文件位置开始;SEEK_END表示从文件末尾开始。
c.使用rewind函数也可将一个流设置到文件起始位置

2).ftello函数和ftell函数相同,而fseeko函数和fseek函数相同,除了偏移量的类型是off_t而不是long

#include <stdio.h>
off_t ftello(FILE* fp);
//成功返回当前文件位置,否则返回(off_t)-1。
int fseeko(File *fp, off_t offset, int whence);
//成功返回0,失败返回非0.

3).想移植到非UNIX系统上运行应用程序应该使用fgetpos和fsetpos

#inlcude <stdio.h>
int fgetpos(FILE *restrict fp, fpos_t *restrict pos);
int fsetpos(FILE *fp, const fpos_t *pos);
//两者成功都返回0,失败返回非0值。

fgetpos返回把文件位置指示器的值存储在由pos指向的对象里。这个值可以被之后的fsetpos调用使用,来重定位流的位置。

8.格式化I/O
1).格式化输出
格式化输出由4个printf函数处理:

#include <stdio.h>
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char *restrict format, ...);
//两者成功都返回字符数,输出错误则返回负值。
int sprintf(char *restrict buf, const char *restrict format, ...);
int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);
//两者成功都返回在字节里存储的字符数量,编码错误返回负值。

printf函数向标准输出写,fprintf向一个指定的流写,而sprintf把格式化的字符串放入到数组buf里。sprintf函数在数组末自动将上一个空字节,但这个空字节没有包含在返回值里。注意sprintf可能为溢出buf指向的缓冲区,这时调用者的执行来保证这个缓冲区足够大。

下面4个printf家族的变体与前4个函数相似,只是参数列表(...)被arg代替。

#include <stdarg.h>
#include <stdio.h>
int vprintf(const char *restrict format, va_list arg);
int vfprintf(FILE *restrict fp, const char *restrict format, va_list arg);
//两者成功都返回输出的字符数,失败返回负值
int vsprintf(char *restrict buf, const char *restrict format, va_list arg);
int vsnprintf(char *restrict buf, size_t n, const char *restrict format, va_list arg);
//两都成功都返回数组存储的字符数,编码错误返回负数。

2).格式化输入

格式化输入由三个scanf函数处理

#include <stdio.h>
int scanf(const char *restrict format, ...);
int fscanf(FILE *restrict fp, const char *restrict format, ...);
int sscanf(const char *restrict buf, const char *restrict format, ...);
//三者都返回被赋值的输入项的数目,输入出错或碰到文件结尾时返回EOF。

scanf家族用来解析一个输入的字符串并转换成指定类型的变量。在格式后的参数包含需要用转换结果初绐化的变量的地址。

和printf家族一样,scanf家族也支持使用可变参数列表的函数,它们由<stdarg.h>指定。

#include <stdarg.h>
#include <stdio.h>
int vscanf(const char *restrict format, va_list arg);
int vfscanf(FILE *restrict fp, const char *restrict format, va_list arg);
int vsscanf(const char *restrict buf, const char *restrict format, va_list arg);
//三者都返回赋好值的输入项的数量,错误或转换前遇到文件结尾时返回EOF

9.实现细节
可以调用fileno来得到流的文件描述符

#include <stdio.h>
int fileno(FILE *fp);
//返回相关联的文件描述符。

10.临时文件

ISO C标准定义了两个由标准I/O库提供的函数,用来协助创建临时文件

#include <stdio.h>
char *tmpnam(char *ptr);
//返回指向唯一的路径名的指针。
FILE *tmpfile(void);
//成功返回文件指针,失败返回NULL

tmpname函数返回一个不与任何已有文件相同的合法路径名的字符串

系统编程--标准IO的更多相关文章

  1. linux系统编程--文件IO

    系统调用 什么是系统调用: 由操作系统实现并提供给外部应用程序的编程接口.(Application Programming Interface,API).是应用程序同系统之间数据交互的桥梁. C标准函 ...

  2. Linux系统编程--文件IO操作

    Linux思想即,Linux系统下一切皆文件. 一.对文件操作的几个函数 1.打开文件open函数 int open(const char *path, int oflags); int open(c ...

  3. Linux系统编程@终端IO

    Linux系统中终端设备种类  终端是一种字符型设备,有多种类型,通常使用tty 来简称各种类型的终端设备.终端特殊设备文件一般有以下几种: 串行端口终端(/dev/ttySn ) ,伪终端(/dev ...

  4. 系统编程--文件IO

    1.文件描述符 文件描述符是一个非负整数,当打开一个现有文件或创建一个新文件时候,内核向进程返回一个文件描述符,新打开文件返回文件描述符表中未使用的最小文件描述符.Unix系统shell使用文件描述符 ...

  5. linux系统编程:IO读写过程的原子性操作实验

    所谓原子性操作指的是:内核保证某系统调用中的所有步骤(操作)作为独立操作而一次性加以执行,其间不会被其他进程或线程所中断. 举个通俗点的例子:你和女朋友OOXX的时候,突然来了个电话,势必会打断你们高 ...

  6. UNIX环境高级编程 标准IO库

    标准I/O库处理很多细节,使得便于用户使用. 流和 FILE 对象 对于标准I/O库,操作是围绕 流(stream)进行的.当用标准I/O打开或创建一个文件时,我们已使一个流与一个文件相关联. 对于A ...

  7. 系统编程--高级IO

    1.非阻塞I/O 非阻塞I/O使我们可以调用不会永远阻塞的I/O操作,例如open,read和write.如果这种操作不能完成,则立即出错返回,表示该操作如继续执行将继续阻塞下去.对于一个给定的描述符 ...

  8. [APUE]标准IO库(下)

    一.标准IO的效率 对比以下四个程序的用户CPU.系统CPU与时钟时间对比 程序1:系统IO 程序2:标准IO getc版本 程序3:标准IO fgets版本 结果: [注:该表截取自APUE,上表中 ...

  9. 【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口

    最近学习linux系统下的应用编程,参考书籍是那本称为神书的<Unix环境高级编程>,个人感觉神书不是写给草鞋看的,而是 写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻 ...

随机推荐

  1. 2017.10.6 Java命名规范及使用情况

    Package 的命名 Package 的名字应该都是由一个小写单词组成. Class 的命名 Class 的名字必须由大写字母开头而其他字母都小写的单词组成 Class 变量的命名 变量的名字必须用 ...

  2. Design and Implementation of Global Path Planning System for Unmanned Surface Vehicle among Multiple Task Points

    Design and Implementation of Global Path Planning System for Unmanned Surface Vehicle among Multiple ...

  3. 公众帐号如何向用户发送emoji表情(php版,附emoji编码表)

    //字节转Emoji表情 function bytes_to_emoji($cp) { if ($cp > 0x10000){ # 4 bytes return chr(0xF0 | (($cp ...

  4. C# as运算符

    一.C# as运算符 as运算符用于执行引用类型的显式类型转换.请阅读C#数据类型. as运算符可以用下面的格式表示: expression as type?expression:引用类型的表达式. ...

  5. Nodejs 调试方法

    nodejs内部提供一个debug机制,可以让程序进入debug模式,供开发者一步一步分析代码发现问题. 共有3中启动参数可以让程序进入debug模式,假设我们要对app.js进行调试. node d ...

  6. SpringMVC注解@RequestParam解析

    1.可以对传入参数指定参数名 1 @RequestParam String inputStr 2 // 下面的对传入参数指定为param,如果前端不传param参数名,会报错 3 @RequestPa ...

  7. 【转载】Callable、FutureTask中阻塞超时返回的坑点

    本文转载自:http://www.cnblogs.com/starcrm/p/5010863.html 案例1: package com.net.thread.future; import java. ...

  8. source insight插件

    直使用sourceinsight编辑C/C++代码,sourceinsight是一个非常好用的编辑工具可以任意定位,跳转,回退,本人一直 使用该工具做C/C++开发,sourceinsight能够满足 ...

  9. GCJ:2008 Round1AA-Minimum Scalar Product(有序数组倒序乘积和最小)

    题目链接:https://code.google.com/codejam/contest/32016/dashboard#s=p0 Minimum Scalar Product This contes ...

  10. POJ:2236-Wireless Network

    Wireless Network Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 34265 Accepted: 14222 D ...