C Primer Plus 第13章 文件输入/输出 13.2 标准I/O

13.2  标准I/O

除了可移植之外,标准I/O包低级I/O有两点优势。第一,标准I/O包中包含很多专用的函数,可以方便地处理不同的I/O问题。例如,printf()将各种类型的数据转换成适合终端的字符串输出。第二,对输入和输出进行了缓冲。也就是说,大块地转移信息(通常每次不少于512个字节),而不是每次一个字节进行转移。例如,当程序个文件时,会把一大块数据复制到缓冲区(一块中介存储区)中。这种缓冲大大提高了数据传输率。

程序清单13.1示范了如何使用标准I/O读取统计的字符个数。

程序清单13.1  count.c程序

/*count.c --使用标准I/O*/
#include <stdio.h>
#include <stdlib.h>  //ANSI C 的exit()原型

int main(int argc,char *argv[])
{
    int ch;    //读取时存储每个字符的位置
    FILE * fp; //文件指针
    long count = 0;

    if(argc != 2)
    {
        printf("Usage: %s filename\n",argv[0]);
        exit(1);
    }
    if((fp=fopen(argv[1],"r")) == NULL)
    {
        printf("Can't open %s\n",argv[1]);
        exit(1);
    }
    while((ch=getc(fp))!=EOF)
    {
        putc(ch,stdout);  //相当于putchar(ch);
        count++;
    }
    fclose(fp);


    printf("File %s has %ld characters\n",argv[1],count);
    return 0;
}

13.2.1  检查命令行参数

首先,程序检查argc的值,查看是否有命令行参数。如果没有,程序打印一条用法提示然后退出。字符串argv[0]是该程序的名称。使用argv[0],而不是显示的使用程序名,则在您改变了可执行文件名后,错误消息也会随之自动改变。

exit()函数关闭所有打开的文件并终止程序。通常的约定的是,正常终止的程序传递值0,非正常终止的程序传递非0值。具体地,ANSI C 要求使用值0或宏EXIT_SUCESS来指示程序成功终止,使用宏EXIT_FAILURE指示程序非成功终止。这些宏和exit()原型在stdlib.h头文件中都可以找到。本书遵循通常的约定使用整数退出值。但为了获得最大的可移植性,您应使用宏。

按照ANSI C,在最初调用的main()中使用return和调用exit()的效果相同。所在在main()中我们一直使用的语句:

    return 0;

和下面这个语句的作用相同:

    exit(0);

但要注意我们所说的是“最初调用”。如果main()在一个递归程序中,exit()仍然会终止程序;但return将控制权移交给递归的前一级,直到最初的一级,此时return才会终止程序。return和exit()的另一个区别在于,即使在除main()之外的函数中调用exit(),它也会终止程序。

13.2.2  fopen( )函数

接下来,程序使用fopen()打开文件。这一函数在stdio.h中声明。它的第一个参数是要打开的文件名;更确切地说,是包含该文件名的字符串的地址第二个参数是用于指定文件打开模式的一个字符串。C库提供了一些可能的模式。如表13.1.

fopen( )函数的模式字符串

模式字符串意义
“r"打开一个文本文件,可以读取文件
"w"打开一个文本文件,可以写入文件,先将文件的长度截为0.如果该文件不存在则先创建之
"a"打开一个文本文件,可以写入文件,向已有文件的尾部追加内容,如果该文件不存在则先创建之
"r+"打开一个文本文件,可以进行更新,也即可以读取和写入文件
"w+"打开一个文本文件,可以进行更新(读取和写入),如果该文件存在则首先将其长度截为0,如果不存在,则先创建之
"a+"打开一个文本文件,可以进行更新(读取和写入),向已有文件的尾部追加内容,如果该文件不存在则先创建之;可以读取整个文体,但写入时只能追加内容

"rb","wb","ab","rb+"

"r+b","wb+","w+b","ab+",

"a+b"

与前面的模式相似,只是使用二进制而非文本模式打开文件

警告:小心!如果使用任何一种"w"模式打开一个已有的文件,文件内容将被删除,以便程序以一个空文件开始操作!

程序成功打开一个文件以后,fopen()函数返回一个文件指针(file pointer),其他I/O函数用这个指针来指定该文件。文件指针是一种指向FILE的指针;FILE是stdio.h中定义的一种派生类型。指针并不指向实际的文件,而是指向一个关于文件的信息的数据包,其中包含文件I/O使用的缓冲区信息。因为标准库中的I/O函数使用缓冲区,所以它们需要知道缓冲区的位置,还需要知道缓冲区的当前缓冲能力以及所使用的文件。这样这些函数在必要的时候可以再次填充或者清空缓冲区。fp指向的数据包中包含全部这些信息(这个数据包是C结构的一个例子,我们将在14章结构和其他数据形式中讨论该主题)。

如果不能打开文件,fopen()返回空指针(也是在stdio.h中定义的)。如果fp为null,程序将退出。磁盘已满、文件名非法、存取权限不够或者硬件问题等都会导致fopen()函数执行失败。

13.2.3  getc( )函数和putc( )函数

这两个函数的工作方式和函数getchar()与putchar()非常相似,不同之处在于您需要告诉getc()和putc()函数它们要使用的文件。所以,下面的方法从标准输入获得一个字符:

    ch = getchar();

但下面的语句表示从指针fp指定的文件中获得一个字符:

    ch = getc(fp);

与之类似,以下语句表示将字符ch写入到FILE指针fpout指定的文件中:

    putc(ch,fpout);

在putc()函数的参数中,首先是字符,然后是文件指针。

程序清单13.1把stdout作为putc()函数的第二个参数。stdout是在stdio.h中定义的与标准输出相关联的文件指针,所以putc(ch,stdout)与putchar(ch)的作用是一样的。实际上,后者一般是通过前者定义的。类似,getchar()使用作为标准输入的getc()定义。

在13.1的例子中通过使用stdout之类的参数,可以很容易地将这段程序改写为向文件进行输出。

13.2.4  文件结尾

程序怎么才能知道是否已经到达文件结尾了呢?

如果在尝试读入字符时发现已经到达文件结尾,getc()函数会返回一个特殊值EOF所以C程序只有在读取 超出文件结尾以后 才会发现文件的结尾。

为了避免试图读取空文件带来的问题,应该对文件输入使用入口条件循环(而不是do while)。鉴于getc()函数(以及其他C输入函数)的设计,程序应该在 进入循环体之前尝试进行第一次读取。

//设计范例

int ch;    //int 来控制EOF
FILE * fp;
fp=fopen("wacky.txt","r");
ch=getc(fp);    //获取初始输入

while(ch!=EOF)
{
    putchar(ch);    //处理输入
    ch=getc(fp);    //获取下一个输入
}

这些语句还可以精简为下面的形式:

int ch;
FILE * fp;
fp=fopen("wacky.txt","r");
while((ch=getc(fp))!=EOF)
{
    putchar(ch);    //处理输入
}

因为输入语句是while判断条件的一部分,所以将在进入循环体之前执行该语句。

这些警告同样适用于其他输入函数,它们也会在遇到文件结尾以后返回一个出错信号(EOF或是NULL指针)。

13.2.5  fclose()函数

fclose(fp)函数关闭由指针fp指定的文件,同时根据需要刷新缓冲区。

更正规的程序也许还要检查是否成功关闭了文件。如果成功关闭,fclose()返回0,否则返回EOF。

if(fclose(fp)!=0)
    printf("Error in closing file %s\n",argv[1]);

磁盘已满、磁盘被移走或者出现I/O错误等等都会导致fclose()函数执行失败。

13.2.6  标准指针文件

stdio.h文件把3个文件指针与3个C程序自动打开的标准文件进行了关联,如表13.2所示

标准文件文件指针一般设备
标准输入stdin键盘
标准输出stdout显示器
标准错误stderr显示器

这些指针都是FILE指针类型,所以可以用作标准I/O函数的参数,就像示例中的fp那样。

转载于:https://my.oschina.net/idreamo/blog/833668

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值