分享

第十三章 文 件

 running_to_you 2017-05-12

第十三章

13.1 C文件概述

文件:文件指存储在外部介质(如磁盘磁带)上数据的集合。

操作系统是以文件为单位对数据进行管理的。

 

文件的分类

●从用户观点:

特殊文件(标准输入输出文件或标准设备文件)

普通文件(磁盘文件)

●从操作系统的角度看,每一个与主机相连的输入

输出设备看作是一个文件。

例:输入文件:终端键盘

输出文件:显示屏和打印机

1)根据文件的内容,可分为程序文件和数据文件,程序文件又可分为源文件、目标文件和可执行文件。

2)根据文件的组织形式,可分为顺序存取文件和随机存取文件。

3)根据文件的存储形式,可分为ASCII码文件和二进制文件。

 ASCII码文件的每1个字节存储1个字符,因而便于对字符进行逐个处理。但一般占用存储空间较多,而且要花费转换时间(二进制与ASCII码之间的转换)。

二进制文件是把内存中的数据,原样输出到磁盘文件中。可以节省存储空间和转换时间,但1个字节并不对应1个字符,不能直接输出字符形式。

C语言对文件的处理方法:

缓冲文件系统:系统自动地在内存区为每一个正在使用的文件开辟一个缓冲区。用缓冲文件系统进行的输入输出又称为高级磁盘输入输出。

非缓冲文件系统:系统不自动开辟确定大小的缓冲区,而由程序为每个文件设定缓冲区。用非缓冲文件系统进行的输入输出又称为低级输入输出系统。

说明:

UNIX系统下,用缓冲文件系统来处理文本文件,用非缓冲文件系统来处理二进制文件。

ANSI C 标准只采用缓冲文件系统来处理文本文件和二进制文件。

C语言中对文件的读写都是用库函数来实现。

13.2 文件类型指针

Turbo C在stdio.h文件中有以下的文件类型声明:

typedef struct

shortlevel;   *缓冲区“满”或“空”的程度*

   unsignedflags; *文件状态标志*

   charfd;        *文件描述符*

   unsignedcharhold; *如无缓冲区不读取字符*

   shortbsize;       *缓冲区的大小*

   unsignedchar*buffer;/*数据缓冲区的位置*/

   unsignedar*curp;/*指针,当前的指向*/

   unsignedistemp;/*临时文件,指示器*/

   shorttoken;/*用于有效性检查*/FILE

在缓冲文件系统中,每个被使用的文件都要在内存中开辟一

FILE类型的区,存放文件的有关信息。

FILE类型的数组:

FILE f5;定义了一个结构体数组f,它有5个元素,可以用来存放5个文件的信息。

文件型指针变量:

FILE  *fpfp是一个指向FILE类型结构体的指针变量。可以使fp指向某一个文件的结构体变量,从而通过该结构体变量中的文件信息能够访问该文件。如果有n个文件,一般应设n个指针变量,使它们分别指向n个文件,以实现对文件的访问。

13.3 文件的打开与关闭

.文件的打开(fopen函数)

函数调用:

FILE  *fp

fpfopen(文件名,使用文件方式);

①需要打开的文件名,也就是准备访问的文件的名字;

②使用文件的方式(“读”还是“写”等);

③让哪一个指针变量指向被打开的文件。

.文件的关闭(fclose函数)

函数调用:

fclose(文件指针);

函数功能:

使文件指针变量不指向该文件,也就是文件指针变量与文件“脱钩”,此后不能再通过该指针对原来与其相联系的文件进行读写操作。

返回值:

关闭成功返回值为0;否则返回EOF(-1)

13.4 文件的读写

一、字符输入输出函数(fputs()fgets())

1.fputs函数

函数调用:

fputs ( chfp )

函数功能:

将字符(ch的值)输出到fp所指向的文件中去。

返回值:

如果输出成功,则返回值就是输出的字符;

如果输出失败,则返回一个EOF

2.fgets函数

函数调用:

chfgetsfp);

函数功能:

从指定的文件读入一个字符,该文件必须是以读或读写方式打开的。

返回值:

读取成功一个字符,赋给ch。

如果遇到文件结束符,返回一个文件结束标志EOF

常见的读取字符操作

从一个文本文件顺序读入字符并在屏幕上显示出来:

   ch = fgetcfp);

   whilech=EOF

  {

       putcharch);

        ch = fgetcfp);

 

注意:EOF不是可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于-1时,表示读入的已不是正常的字符而是文件结束符。

常见的读取字符操作

从一个二进制文件顺序读入字符:

   while(!feoffp))

  {

        ch = fgetcfp);

 

注意:ANSI C提供一个feof()函数来判断文件是否真的结束。如果是文件结束,函数feoffp)的值为1(真);否则为0(假)。以上也适用于文本文件的读取。

#include <stdlib.h>

#include <stdio.h>

void   main(void)

 {     FILE *fp;

       char ch,filename[10];

       scanf("%s",filename);

       if((fp=fopen(filename,"w"))==NULL)

{

                  printf("cannot open file\n");

                  exit(0); /*终止程序*/

}

       ch=getchar( ); /*接收执行scanf语句时最后输入的回车符 */

       ch=getchar( ); /* 接收输入的第一个字符 */

       while(ch!='#)

       {

fputc(ch,fp);putchar(ch);

                           ch=getchar();

}

                     fclose(fp);

     }

运行情况如下:
file1.c              (输入磁盘文件名)
computer and c#(输入一个字符串)
computer and c    (输出一个字符串)

 

 

 


#include <stdlib.h>

#include <stdio.h>

 main( )

{

FILE *in,*out;

        char ch,infile[10],outfile[10];

        printf("Enter the infile name:\n");

scanf("%s",infile);

        printf("Enter the outfile name:\n");

        scanf("%s",outfile);

        if((in=fopen(infile,"r"))==NULL)

        {       

printf("cannot open infile\n");

           exit(0);

}

        if((out=fopen(outfile,"w"))==NULL)

    {       

printf("cannot open outfile\n");

        exit(0);

    }

    while(!feof(in))fputc(fgetc(in),out);

    close(in);

        fclose(out);

}

运行情况如下:
Enter the infile name
file1.c(输入原有磁盘文件名
Enter the outfile name:
file2.c (输入新复制的磁盘文件名) 
程序运行结果是将file1.c文件中的内容复制到
file2.c中去。 

 

#include <stdlib.h>

#include <stdio.h>

main(int argc,char *argv[ ])

{

FILE *in,*out;

        char ch;

        if (argc!=3)

 {     

printf("You forgot to enter a filename\n");

                   exit(0);

 }

         if((in=fopen(argv[1],"rb"))==NULL)

         {       

printf("cannot open infile\n");

             exit(0);

}

    if((out=fopen(argv[2],"wb"))==NULL)

         {       

printf("cannot open outfile\n");

             exit(0);

}

         while(!feof(in)) fputc(fgetc(in),out);

        fclose(in);

 fclose(out);

}

运行方法:
设经编译连接后得到的可执行文件名为a.exe,则在DOS命令工
作方式下,可以输入以下的命令行:
C>a file1.c file2.c 
file1.c和file2.c,分别输入到argv[1]
和argv[2]中,argv[0]的内容为a,argc的
值等于3 。

 

 

 

 

 

二、数据块读写函数(fread()fwrite())

函数调用:

fread (buffer,size,countfp);

fwrite(buffer,size,count,fp);

参数说明:

buffer:是一个指针。

fread 来说,它是读入数据的存放地址。

fwrite来说,是要输出数据的地址(均指起始地址)。

size  要读写的字节数。

count 要进行读写多少个size字节的数据项。

fp    文件型指针。

使用举例:

  若文件以二进制形式打开:

  fread(f,4,2,fp);

  此函数从fp所指向的文件中读入24个字节的数据,存储到数组f中。

使用举例:

若有如下结构类型:

struct student_type

{

char name[10];

int num;

        int age;

        char addr[30];}stud[40];

}

可以用freadfwrite来进行数据的操作:

for(i=0;i<40;i++)

 fread(&studi],sizeof(struct student-type)1fp); 

for(i=0;i<40,i++)

fwrite(&studi],sizeof(struct student-type)1fp); 

使用举例:

13.3从键盘输入4个学生的有关数据,然后把它们转存到磁盘文件上去。

#include <stdio.h>

#define SIZE 4

struct student_type

{        char name[10];

    int num;

    int age;

    char addr[15];

}stud[SIZE]; /*定义结构*/

void save( )

{

FILE *fp;

        int i;

        if((fp=fopen("stu-list","wb"))==NULL)

{

 printf("cannot open file\n");

                return;

}

        for(i=0;i<SIZE;i++)/*二进制写*/

if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)

                 printf(file write error\n);/*出错处理*/

        fclose(fp); } /*关闭文件*/  

main()

{

int i;

                 for(i=0;i<SIZE;i++)/*从键盘读入学生信息*/

scanf("%s%d%d%s",stud[i].name,&stud[i].num,&stud[i].age,stud[i].addr);

    save( );

}/*调用save()保存学生信息*/

运行情况如下:
输入4个学生的姓名、学号、年龄和地址:
       Zhang 1001 19 room-101
       Fun      1002  20  room-102
       Tan      1003  21  room-103
       Ling    1004  21  room-104 

 

 

 

 


 #include <stdio.h>

 #define SIZE 4

 struct student_type

 {        char name[10];

      int num;

      int age;

      char addr[15];

}stud[SIZE];    

 main( )

{        int i;

         FILE*fp;

         fp=fopen("stu-list","rb");

         for(i=0;i<SIZE;i++)

    {

fread(&stud[i],sizeof(struct student_type),1,fp);

            printf("%\-10s %4d      %4d   %\-15s\n",stud[i].name,stud[i].num,stud[i].          age,stud[i].addr);

}

         fclose (fp);

    }

屏幕上显示出以下信息:
Zhang 1001      19    room-101
Fun     1002      20    room-102
Tan     1003      21    room-103
Ling   1004      21    room-104 

 

 

 

如果已有的数据已经以二进制形式存储在一个磁盘文件“stu-dat”中,要求从其中读入数据并输出到“stu-list”文件中,可以编写一个load函数,从磁盘文件中读二进制数据。

void load( )

 {

FILE *fp;int i;

       if((fp=fopen("stu-dat","rb"))==NULL)

    {       

printf("cannot open infile\n");

           return;

}

       for(i=0;i<SIZE;i++)

             if(fread(&stud[i],sizeof(struct student_type),1,fp)!=1)

           {

if(feof(fp)) {fclose(fp); return;}

                         printf("file read error\n");

}

  fclose (fp)

}

三、格式化读写函数(fprintf()fscanf())

函数调用:

fprintf ( 文件指针,格式字符串,输出表列);

fscanf  ( 文件指针,格式字符串,输入表列);

函数功能:

从磁盘文件中读入或输出字符。

例:

fprintf(fp,%d,%6.2f,i,t);

Fscanf (fp,%d,%f,&i,&t);

注意:

fprintffscanf函数对磁盘文件读写,使用方便,容易理解,但由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换成字符,花费时间比较多。因此,在内存与磁盘频繁交换数据的情况下,最好不用fprintffscanf函数,而用freadfwrite函数。

四、其他读写函数

putw()getw()

函数调用:

putw(int i,FILE * fp)

int i = getw(FILE * fp)

函数功能:

对磁盘文件中读写一个字(整数)。

例:

putw(10,fp);

i = getw(fp);

gutw函数定义如下:

gutw(FILE *fp)

{

   char s;

   s=char *&i;

   s[0] = getc(fp);

   s[1] = getc(fp);

   return i;

  }

用户自定义读取其他类型数据的函数。

向磁盘文件写一个实数(用二进制方式)的函数putfloat :

putfloat(float num,FILE *fp)

{

         char *s;

         int count;

         s = (char*)&num;

         for(count = 0;count < 4;count++)

         putc(s[count],fp);

 }

fgets函数

函数作用:

从指定文件读入一个字符串。

函数调用:

fgets(str,n,fp);

fp指向的文件输入n-1个字符,在最后加一个’\0’。

返回值:

str的首地址。

fputs函数

函数作用:

向指定的文件输出一个字符串。

函数调用:

fgets(china,fp);

第一个参数可以是字符串常量、字符数组名或字符型指针。字符串末尾的′\0′不输出。

返回值:

输入成功,返回值为0

输入失败,返回EOF

13.5 文件的定位

#include<stdio.h>

 main()

{        FILE *fp1,*fp2;

        fp1=fopen("file1.c","r");

         fp2=fopen("file2.c","w");

    while(!feof(fp1)) putchar(getc(fp1));

     rewind(fp1);

          while(!feof(fp1))

     putc(getc(fp1),fp2);

     fclose(fp1);fclose(fp2);

}

顺序读写和随机读写

顺序读写:

位置指针按字节位置顺序移动。

随机读写:

读写完上一个字符(字节)后,并不一定要读写其后续的字符(字节),而可以读些文件中任意位置上所需要的字符(字节)。

fseek函数(一般用于二进制文件)

函数功能:

改变文件的位置指针。

函数调用形式:

fseek(文件类型指针,位移量,起始点)

起始点:文件开头         SEEK_SET     0

        文件当前位置     SEEK_CUR     1

        文件末尾         SEEK_END     2

位移量:以起始点为基点,向前移动的字节数。一般

        要求为long型。

fseek函数应用举例

fseek(fp100L,0);//将位置指针移到离文件头100个字节处。

fseek(fp50L 1);//将位置指针移到离当前位置50个字节处。

fseek(fp50L 2);//将位置指针从文件末尾处向后退10个字节。

#include <stdlib.h>

#include<stdio.h>

 struct student_type

{       char name[10];

        int num;

        int age;

        char sex;

 }stud[10];   

 main()

{  int i;

   FILE  *fp;

   if((fp=fopen("stud-dat","rb"))==NULL)

   {

printf("can not open file\n");

             exit(0);

   }

  for(i=0;i<10;i+=2)

  {

    fseek(fp,i*sizeof(struct student_type),0);

      fread(&stud[i], sizeof(struct student_type),1,fp);

      printf(%s %d %d %c\n,stud[i].name,stud[i].num,stud[i].age,stud[i].sex);

}

 fclose(fp);

}

ftell函数

函数作用:

得到流式文件中的当前位置,用相对于文件开头的位移量来表示。

返回值:

返回当前位置,出错时返回-1L

应用举例:

i = ftell(fp);

if(i==-1L) printf(error\n);

13.6 出错的检测

ferror函数

调用形式:

ferror(fp);

返回值:

返回0,表示未出错;返回非0,表示出错。

在调用一个输入输出函数后立即检查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。

clearerr函数

调用形式:

clearerr(fp);

函数作用:

使文件错误标志和文件结束标志置为0

只要出现错误标志,就一直保留,直到对同一文件调用clearerr函数或rewind函数,或任何其他一个输入输出函数。

13.7 文件输入输出小结

 

 

 

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多