第13章 文件输入/输出 (2)

发布于 28 天前  48 次阅读


13.3 一个简单的文件压缩程序

下面的程序示例把一个文件中选定的数据拷贝到另一个文件中。该程序同时打开了两个文件,以“r”模式打开一个,以“w”模式打开另外一个。该程序以保留每3个字符中的第1个字符的方式压缩第一个文件的内容。最后,把压缩后的文本存入第2个文件。第2个文件的名称是第1个文件名加上.red后缀(此处的red代表reduced)。
使用命令行参数,同时打开多个文件,以及在原文件名后面加上后缀,都是相当有技巧的。这种压缩方式有限,但是也有它的用途(很容易把该程序改成用标准I/O而不是命令行参数提供文件名)
//reduceto.c    --把文件压缩成原来的1/3!
#include<stdio.h>
#include<stdlib.h>    //--提供exit()原型
#include<string.h>    
#define LEN 40

int main(int argc,char *argv[])
{
    FILE *in,*out;
    int ch;
    char name[LEN];     //存储文件输出名字
    int count = 0;

    //检查命令行参数
    if(argc < 2)
    {
        fprintf(stderr,"Usage: %s filename\n",argv[0]);
        exit(EXIT_FAILURE);
     } 
    //设置输入
    if((in = fopen(argv[1],"r"))==NULL)
    {
        fprintf(stderr,"I couldn't open the file \" %s \"\n",argv[1]);
        exit(EXIT_FAILURE);
    }
    strncpy(name,argv[1],LEN-5);    //拷贝文件名
    name[LEN -5] = '\0';
    strcat(name,".red");
    if((out = fopen(name,"w"))==NULL)
    {
        fprintf(stderr,"Can't create output file.\n");
        exit(3);
    }
    //拷贝数据
    while((ch = getc(in))!= EOF)
    {
        if(count++ %3 ==0)
            putc(ch,out);   //打印3个字符中的第1个字符
    }
    //收尾工作
    if(fclose(in)!=0)
    {
        fprintf(stderr,"Error in closing files\n");
    }

    return 0;
 } 
fprintf()和printf()类似,但是fprintf()的第1个参数必须是一个文件指针,程序中使用的stderr指针把错误消息发送至标准错误,C标准通常都这么做。
为了构造新的输出文件名,该程序使用strncpy()把名称拷贝到数组name中。参数LNE - 5为.red后缀和末尾的空字符预留了空间。如果argv[1]字符串比LEN -5长,就拷贝不了空字符。出现这种请款时,程序就会添加空字符。调用strncpy()后,name中的第1个空字符在调用strcat()函数时,被.red的.覆盖,生成了name.red。程序中还检查了是否成功打开了名为eddy.red的文件。这个步骤在一些环境中相当重要,因为像strange.c.red这样的文件命可能是无效的。例如,在传统的DOS环境中,不能再后缀名后面添加后缀名(MS-DOS使用的方法是用.red替换现有的后缀名,所以strange.c将变成strange.red.例如,可以用strchr()函数定位,然后只拷贝点前面的部分即)。
该程序同时打开了两个文件,所以我们要声明两个指针FILE指针,注意,程序都是单独打开和关闭每个文件。同时打开的文件数量是有限的,取决于系统。范围一般是10~20.相同的文件指针可以处理不同的文件,前提是这些文件不需要同时打开。

13.4 文件I/O:fprintf()、fscanf()、fgets()、和fputs().

前面章节介绍的I/O函数都类似于文件I/O函数。它们主要的区别是要用FILE指针指定待处理的文件。与getc()、putc()类似,这些函数都要求用指向FILE的指针(如,stdout)指定一个文件,或者使用fopen()的返回值。

13.4.1 fprintf()和fscanf()函数

文件I/O函数fprintf()和fscanf()函数的工作方式与printf()和scanf()类似,区别在于前者要用第1个参数指定待处理的文件。
//addaword.c    --使用fprintf()、fscanf()和rewind()
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 41

int main(void)
{
    FILE *fp;
    char words[MAX];

    if((fp = fopen("wordy","a+")) == NULL )
    {
        fprintf(stderr,"Can't open \"wordy\" file.");
        exit(EXIT_FAILURE);
    }

    puts("Enter words to add to the file;press the #");
    puts("Key at the beginning of a line to terminate.");
    while((fscanf(stdin,"%40s",words)==1)&&(words[0] != '#'))
        fprintf(fp,"%s\n",words);

    puts("File contents:");
    rewind(fp); //返回到文件开始处
    while(fscanf(fp,"%s",words) == 1)
        puts(words);
    puts("Done!");
    if(fclose(fp) != 0)
        fprintf(stderr,"Error closing file\n");

    return 0;
}

file

该程序可以在文件中添加单词,使用“a+”模式,程序可以对文件进行读写操作。首次使用该程序,它将会创建wordy文件,以便把单词存入其中。随后再使用该程序,可以在wordy文件后面添加单词。虽然“a+”模式只允许在文件末尾添加内容,但是该模式下可以读整个文件。rewind()函数让程序回到文件开始处,方便 while循环打印整个文件夹的内容。rewind()接受一个文件指针作为参数。

fprintf()和fscanf()的工作方式与printf()和scanf()类似。但是,与putc()不同的是,fprintf()和fscanf()函数都把FILE指针作为第1个参数,而不是左后一个参数。

13.4.2 fgets()和fputs()

fgets()函数。它的第一个参数和gets()函数一样,也表示存储输入位置的地址(char *类型);第2个参数是一个整数,表示待输入字符串的大小。最后一一个参数是文件指针,指定待读取的文件。下面是一个调用该函数的例子:
fgets(buf,STLEN,fp);
这里,buf是char类型数组的名称,STLEN是字符串的大小,fp是指向FILE的指针。
fgets()函数读取输入直到第1个换行符后面,或者读到文件结尾,或者读取STLEN - 1 个字符,以上面的fgets()为例子)。然后,fgets()在末尾添加一个空字符使之称为一个字符串。字符串的大小是其子夫数加上一个空字符。如果fgets()在督导字符上线之前已经读完一整行,他会把表示行结尾的换行符放在空字符前面。fgets()函数在遇到EOF时返回NULL值,可以利用这一机制是否到达文件结尾,如果未遇到EOF则返回之前传给它的第一个参数地址。
fputs()函数接受两个参数;第1个是字符串的地址;第2个是文件指针。该函数根据传入地址找到的字符串写入指定的文件中中。和puts()函数不同,fputs()在打印字符串时候,不会在其末尾添加换行符。下面是一个调用该函数的例子。
fputs(buf,fp);
这里,buf是字符串的地址,fp用于指定目标文件。
由于fgets()保留了换行符,fputs()就不会再添加换行符,它们配合的非常好。

擦肩而过的概率