第五章 标准I/O库

来源:互联网 发布:上市公司网络投票规则 编辑:程序博客网 时间:2024/06/05 03:29

5.2 流和file对象

      当用标准I/O库打开或创建一个文件时,我们已使一个流和一个文件相关联。

      当一个流最初被创建时,它并没有定向。如若在未定向的流上使用个多字节I/o函数,则将该流的定向设置为宽定向的,若在未定向的流上使用一个单字节I/O函数,则将该流的定向设置为字节定向的。只有两个函数可改变流的定向。freopen清楚一个流的定向,fwide函数设置流的定向。

   #include <stdio.h>

   #include <wchar.h>

   int fwide(FILE * fp ,int mode); 返回值:若流是宽定向的则返回正值, 若流是字节定向的则返回负值,或者若流是未定向的则返回0

  根据mode参数的不同值,fwide函数执行不同的工作:
  若mode参数值为负,fwide将试图使指定的流是字节定向的

  若mode参数值为正,fwide将试图使指定的流是宽定向的

  若mode参数值为0 ,fwide将不试图设置流的定向,但返回标识该流定向的值。

 

5.3 保准输入 标准输出 和标准出错

    这三个标准I/O流通过预定义文件指针stdin,stdout 和stderr加以引用。这三个文件指针同样定义在头文件<stdio.h>中。

5.4 缓冲

   标准I/O库提供缓冲的目的是尽可能减少使用read和writte调用次数.标准I/O提供了三种类型的缓冲:

   (1)全缓冲.在填满标准I/O缓冲区后才进行实际I/O操作。对于驻留在磁盘上的文件通常是由标准I/O库实施全缓冲的。

   (2)行缓冲。当在输入和输出中遇到换行符时,标准I/O库执行I/O操作。

   (3)不带缓冲。标准I/O库不对字符进行缓冲存储。 标准出错流stderr通常是不带缓冲的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个换行符。

  对任何一个给定的流, 如果我们并不喜欢这些系统默认的情况,则可调用下列两个函数中的一个更改缓冲类型:

  #include<stdio.h>

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

 int   setvbuf(FILE * restrict fp , char * restrict buf , int mode , size_t size); //返回值:若成功则返回0, 若出错则返回非0值

可以使用setbuf函数打开或关闭缓冲机制。为了带缓冲进行I/O,参数buf必须指向一个长度为BUFSIZ的缓冲区(该常量定义在<stdio.h>中)。通常在此之后该流就是全缓冲的, 但是如果该流与一个终端设备相关,那么某些系统也可将其设置为行缓冲。为了关闭缓冲,将BUF设置为NULL。

使用setvbuf,我们可以精确的指定所需的缓冲类型。这里用mode参数实现的。

_IOFBF 全缓冲  _IOLBF行缓冲  _IONBF不带缓冲。

第五章  标准I/O库 - night person - 夜归人

 #include<stdio.h>

int fflush(FILE * fp); 成功返回0, 出错返回EOF

此函数使该流所有未写的数据都被传送至内核。作为一个特例,如若fp是NULL ,则此函数将导致所有输出流被冲洗。

 

5.5打开流

#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

fopen打开一个指定的文件。

freopen在一个指定的流上打开一个指定的文件,若该流已经打开,则先关闭该流。若该流已经定向,则freopen 清除该定向。

此函数一般用户将一个指定的文件打开为一个预定义的流:标准输入 标准输出或标准出错。

fdopen获取一个现有的文件描述符(我们可能从open ,dup ,dup2,fcntl ,pipe,socket socketpaire 或accept函数得到此文件描述符)并使一个标准的I/O流与该描述符相结合。

第五章  标准I/O库 - night person - 夜归人

 


#include <stdio.h>

int fclose(FILE * fp); 返回值:若成功则返回0 , 若出错则返回EOF

在该文件被关闭之前,冲洗缓冲区中的输出数据。丢弃缓冲区中的任何输入数据。如果标准I/O库已经为该流自动分配了一个缓冲区,则释放此缓冲区。

当一个进程正常终止时(直接调用exit函数,或从main函数返回),则所有带写缓冲数据的标准I/O流都会被冲洗,所有打开的标准I/O流都会被关闭。

 

 

5.6 读和写

一旦打开了流,则可在三种不同类型的非格式化I/O中进行选择,对其进行读写操作:

1.每次一个字符的I/O。 一次读或写一个字符,如果流是带缓冲的,则标准I/O函数会被处理所有缓冲。

2.每次一行的I/O。 如果想要一次读或写一行,则使用fgets 和fputs.每行都以一个换行符终止。当调用fgets时,应该说能处理的最大行长。

3.直接I/O.fread和fwrite函数支持这种类型的I/O.每次I/O操作读或写某种数量的对象,而每个对象具有指定的长度。这两个函数常用于从二进制文件中每次读或写一个结构。

1.输入函数

以下三个函数可用于一次读一个字符。

#include <stdio.h>

int getc(FILE *fp);

int fgetc(FILE *fp);

int getchar(void);

//三个函数的返回值:若成功则返回下一个字符,若已到达文件结尾或出错则返回EOF。

getchar等价于getc(stdin).前两个函数的区别是 getc可被实现为宏,而fgetc则不能实现为宏。 这意味着:

(1)getc的参数不应该是具有副作用的表达式

 (2)因为fgetc一定是一个函数,所以可以得到其地址。这就允许将fgetc的地址作为一个参数传递给另外一个函数。

 

不管是出错还是到达文件末尾,这三个函数都返回同样的值。为了区分这两种不同的情况,必须调用ferror或feof.

#include <stdio.h>

int ferror(FILE *fp);

int feof(FILE *fp ); //两个函数返回值:若条件为真则返回非0 真,否则返回0 假

void clearerr(FILE *fp);

在大多数实现中,为每个流在FILE对象中维持了两个标志 出错标志 文件结束标志 调用clearerr则清除这两个标志。

从流中读取数据后,可以调用ungetc将字符再压送回流中。

#include <stdio.h>

int ungetc(int c FILE *fp);  //若成功 则返回0  若出错则返回EOF

注意:用ungetc压送回字符时,并没有将他们写到文件中或设备上,只是将它们写回标准I/O库的流缓冲区中。

 

2.输出函数

#include <stdio.h>

int putc(int c ,FILE *fp);

int fputc(int c , FILE *fp);

int putchar(int c);  // 三个函数返回值:若成功则返回C 若出错则返回EOF

 

 

5.7每次一行I/O

下面两个函数提供每次输入一行的功能

#include<stdio.h>

char * fgets(char * restrict buf, int n ,FILE * restrict fp);

char * gets(char * buf); //两个函数返回值:若成功则返回buf,若已到达文件结尾或出错则返回NULL

说明:gets是一个不推荐使用的函数。会造成缓冲区溢出。

fputs 和 puts提供每次输出一行的功能.

 #include<stdio.h>

int fputs(const char * restrict str, FILE * restrict fp);

int puts(const char * str); //两个函数返回值:若成功则返回非负值,若出错则返回EOF

函数fputs将一个以null符终止的字符串写到指定的流,尾端的终止符null补写出。

puts将一个以null符终止的字符串写到标准输出,终止符不写出。但是,puts然后又将一个换行符写到标准输出。

 

5.8 标准I/O的效率

一般而言 标准I/O和 无缓冲区I/O速度差不多,  无缓冲 要选择缓冲区的大小为blocksize,这样速度快一些。

 

5.9二进制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 prt,size_t size, size_t nobj, FILE * restrict fp); //两个函数的返回值:读或写的对象数

fread 和fwrite 返回读或写的对象数。对于读,如果出错或达到文件尾端,则此数字可以少于nobj.在这种情况下,应调用ferror或feof以判断究竟属于哪一种情况。对于写,如果返回值少于所要求的nobj,则出错。

 

 5.10 定位流

有三种方法定位标准I/O流。

1.ftell和fseek函数,它们假定文件的位置可以存放在一个长整型中。

2.ftello和fseeko函数,可以使文件偏移量不必一定使用长整型。它们使用off_t数据类型代替了长整型。

3.fgetpos和fsetpos函数,他们使用一个抽象数据类型fpos_t记录文件的位置。这种数据类型可以定义为记录一个文件位置所需的长度。

 

5.11格式化I/O

1.格式化输出

   printf,frpintf ,sprintf , snprintf

下列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 * restrct buf, size_t n , const char * restrict format, va_list arg);

//两个函数的返回值:若成功则返回存入数组的字符数,若编码出错则返回负值

 

2.格式化输入

scanf, fscanf ,sscanf

变体的scanf类:

vscanf , vfscanf , vsscanf

 

 

5.12实现细节

每个标准I/O流都有一个与其相关联的文件描述符,可以对一个流调用fileno函数以获得其描述符

#include<stdio.h>

int fileno(FILE * fp); //返回值:与该流相关联的文件描述符

 

eg:

#include "apue.h"
void    pr_stdio(const char *, FILE *);

int main(void)
{
    FILE    *fp;
    fputs("enter any character\n", stdout);
    if (getchar() == EOF)
        err_sys("getchar error");
    fputs("one line to standard error\n", stderr);

    pr_stdio("stdin",  stdin);
    pr_stdio("stdout", stdout);
    pr_stdio("stderr", stderr);

    if ((fp = fopen("/etc/motd", "r")) == NULL)
        err_sys("fopen error");
    if (getc(fp) == EOF)
        err_sys("getc error");
    pr_stdio("/etc/motd", fp);
    exit(0);
}

void pr_stdio(const char *name, FILE *fp)
{
    printf("stream = %s, ", name);
    /*
     * The following is nonportable.
     */
    if (fp->_IO_file_flags & _IO_UNBUFFERED)
        printf("unbuffered");
    else if (fp->_IO_file_flags & _IO_LINE_BUF)
        printf("line buffered");
    else /* if neither of above */
        printf("fully buffered");
    printf(", buffer size = %d\n", fp->_IO_buf_end - fp->_IO_buf_base);
}

 

5.13 临时文件

#include<stdio.h>

char * tmpnam(char * ptr); //返回值:指向唯一路径名的指针

FILE * tmpfile(void ); //返回值:若成功则返回文件指针,若出错则返回NULL

若ptr是NULL,则所产生的路径名存放在一个静态区中,指向该静态区的指针作为函数值返回。下一次调用tmpname时,会重写该静态区。 若ptr不是NULL,则认为它指向长度至少是L_tmpname个字符的数组。 L_tmpname定义在头文件<stdio.h>中
注:tempnam是tmpnam的一个变体,允许加前缀


 

5.14标准I/O的替代软件

标准I/O库的一个不足之处是效率不高,这与它需要复制的数据量有关。当使用每次一行函数fgets和fputs时,通常需要复制两次数据:一次是在内核和标准I/O缓冲之间。第二次是在标准I/O缓冲区和用户程序中的行缓冲区之间。

0 0
原创粉丝点击