轻松学习C语言 第十章 文件

 

C语言文件操作

①C文件概述②文件类型指针③文件的打开与关闭④文件的读写⑤文件的定位⑥出错的检测⑦文件输入输出小结

本章学习目标

  1. 理解文本文件和二进制文件的区别;
  2. 理解 FILE *fp 文件指针;
  3. 能够用函数fopen和fclose打开和关闭文件;
  4. 掌握常用的文件读/写函数;

10.1  C文件概述

文件:存储在外部介质上数据的集合,是操作系统数据管理的单位。

使用数据文件的目的

1、数据文件的改动不引起程序的改动——程序与数据分离。

2、不同程序可以访问同一数据文件中的数据——数据共享。

3、能长期保存程序运行的中间数据或结果数据。

文件分类

按文件的逻辑结构:

  1. 记录文件:由具有一定结构的记录组成(定长和不定长)
  2. 流式文件:由一个个字符(字节)数据顺序组成

按存储介质:

  1. 普通文件:存储介质文件(磁盘、磁带等)
  2. 设备文件:非存储介质(键盘、显示器、打印机等)

按数据的组织形式:

  1. 文本文件: ASCII文件,每个字节存放一个字符的ASCII码
  2. 二进制文件:数据按其在内存中的存储形式原样存放

C语言的文件是流式文件。

所谓流就是一系列的字节或者字符,输入输出数据流的开始和结束仅受程序控制,而不受物理符号(如回车符)的控制。这种文件称为流式文件。

文本文件特点:存储量大、速度慢、便于对字符操作

二进制文件特点:存储量小、速度快、便于存放中间结果

文本文件与二进制文件的区别:

①计算机的存储在物理上是二进制的,所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上的.这两者只是在编码层次上有差异。

②二进制流比文本流节省空间,且不用进行对\n的转换,这样可以大大加快流的速度,提高效率。因而,对于含有大量数字信息的数字流,可以采用二进制流的方式;对于含有大量字符信息的流,则采用文本流的方式。

③文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等等。

二进制文件是基于值编码的文件。

文件处理方法

  1. 缓冲文件系统:高级文件系统,系统自动为正在使用的文件开辟内存缓冲区。可减少主机和外部设备频繁交换数据的次数
  2. 非缓冲文件系统:低级文件系统,由用户在程序中为每个文件设定缓冲区

10.2  文件类型指针

文件结构体类型FILE

缓冲文件系统为每个正使用的文件在内存开辟文件信息区文件信息用系统定义的名为FILE的结构体描述

定义文件类型变量

存放文件的信息

如:定义FILE类型数组,存放若干文件信息:FILE  f[5];

定义文件型指针变量,指向FILE类型结构体变量,通过该结构体变量中的文件信息访问文件。

如:FILE  *fp;

用法:

文件打开时,系统自动建立文件结构体,并把指向它的指针返回来,程序通过这个指针获得文件信息,访问文件

如:fp=fopen("a1","r");

文件关闭后,它的文件结构体被释放

经过定义的文件指针,就可以用来指向一个文件!

10.3  文件的打开与关闭

C文件操作用库函数实现,包含在stdio.h

文件使用方式:打开文件→文件读/写→关闭文件

系统自动打开和关闭三个标准文件:

  1. 标准输入------键盘                stdin
  2. 标准输出------显示器            stdout
  3. 标准出错输出-----显示器     stderr

1.文件的打开(fopen函数)

函数原型: FILE   *fopen(char  *name,char *mode)

调用方式:fopen("文件名","使用文件方式")

例:FILE *fp;fp=fopen("d:\\user\\myfile.txt","r");

返回值:正常打开,返回指向文件结构体的指针;打开失败,返回 NULL 

FILE   *fp;
fp=fopen(“aa.c","w");
if(fp==NULL)
{ 
   printf("File open error!\n");
   exit(0);     /*关闭所有文件终止调用*/
}

r:读方式;

w:写方式;

a:追加方式;

rb/wb/ab:二进制方式;

+:既可读又可写

2.文件的关闭(fclose函数)

作用:使文件指针变量与文件“脱钩”,释放文件结构体和文件指针

FILE  *fp;

fp=fopen(“a.txt”,“r”);

fclose(fp);

返回值:用于表示文件是否被正确地关闭,如果文件顺利关闭,该值为0,否则为-1(EOF)。

返回值可以用ferror函数测试

10.4  文件的读写

文件打开之后,就可以对它进行读与写的操作了。

读/写文件中的一个字符

1.fputc函数(putc函数)

函数原型:int  fputc(int c, FILE *fp)

功能:把一字节代码c写入fp指向的文件中

返值:正常,返回c;出错,为EOF(-1)

2.fgetc函数(getc函数)

函数原型:int  fgetc(FILE *fp)

功能:从fp指向的文件中读取一字节代码

返值:返回读到的代码值;读到文件尾或出错为EOF(-1)

3.feof函数

调用方式:feof(fp)

功能:对于二进制文件读取时判断文件是否结束。

返值:若到文件末尾,为真(非零) 

文本文件: 结束为真,非零  

//二进制或文本文件:
#include "stdio.h"
void main()
{ 
	FILE  *fp; 
	char ch;
	fp=fopen("d2.dat","r"); //fopen("文件路径","文件操作");
	ch=fgetc(fp);
	while(ch!=EOF)
	{ 
	 putchar(ch);
	 ch=fgetc(fp);
	}
	fclose(fp);
}

 

二进制或文本文件:

//二进制或文本文件:

#include "stdio.h"
void main()
{
    FILE  *fp;
    char ch;
    fp=fopen("d2.dat","r");
    ch=fgetc(fp);
    while(!feof(fp))
    {
        putchar(ch);
        ch=fgetc(fp);
    }
    fclose(fp);
}

从键盘输入一些字符,逐个把它们送到磁盘上去,直到输入一个“#”为止。

//从键盘输入一些字符,逐个把它们送到磁盘上去,直到输入一个“#”为止。
#include <stdio.h>
#include <stdlib.h>
void main(){
	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();//第一个输入的字符被赋给变量ch
	while(ch!='#'){
		fputc(ch,fp);//字符被写入filename表示的文件中
		putchar(ch); //字符被输出到显示器
		ch = getchar();
	}
	putchar(10);//向屏幕输出一个换行符
	fclose(fp); //关闭文件
}

流程图:

 

例  将一个磁盘文件中的信息复制到另一个磁盘文件中。

//将一个磁盘文件中的信息复制到另一个磁盘文件中。
#include <stdio.h>
#include <stdlib.h>
void 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);
	}
	//将infile的内容复制到outfile
	while(!feof(in))
		fputc(fgetc(in),out);
	fclose(in);
	fclose(out);
}	

例  用main参数,在输入命令行时把两个文件名一起输入。 

#include <stdio.h>
#include <stdlid.h>
void 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], "r"))== NULL)
    { 
		printf("Cannot open infile.\n");
        exit(0);  
	}
    if ((out = fopen(argv[2], "w"))== NULL)
    { 
		printf("Cannot open outfile.\n");
        exit(0);  
	}
    while (!feof(in))  
		fputc(fgetc(in), out);
    fclose(in);   
	fclose(out);  
}

当可执行文件名是:a.exe 输入命令行:C:\>a  file1.c  file2.c 则:file1中内容复制到file2文件中

数据块输入输出函数:

4.fread与fwrite 一般调用形式:

  • fread(buffer,size,count,fp );
  • fwrite(buffer,size,count,fp );

参数说明:

  1. buffer:  要读入的数据块的存放首地址或要输出的数据块的起始地址
  2. size:  每个要读/写的数据块的大小(字节数)
  3. count:   要读/写的数据块的个数
  4. fp:    要读/写的文件指针 返值:成功,返count的值;出错或文件尾,0值。

fread与fwrite 一般用于二进制文件的输入/输出 若文件以二进制形式打开,用fread或fwrite 可读写任何类型的数据

如: fread(f, 4, 2, fp)

例  从键盘输入4个学生的数据,然后转存到磁盘上,并在屏幕上显示磁盘文件的内容。

#include <stdio.h>
#define SIZE 4
struct student_type
{ 
	char name[10];
    int num;
    int age;
    char addr[15];
}stud[SIZE];
void main()
{ 
	void save();
	void display();
	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();
	display(); 
}
void save()
{ 
	FILE *fp;
	int  i;
	// 文件必须是以“二进制”打开的,
	if((fp=fopen("d:\\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);
}
void display()
{ 
	FILE *fp;
	int  i;
	if((fp=fopen("d:\\stu_list","rb"))==NULL)
	{ 
		printf("cannot open file\n");   
		return;
	}
	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);
}

按指定格式读写文件的函数:

5.fprintf和fscanf 一般调用格式:

  1. fscanf(fp,格式字符串,输入列表);
  2. fprintf(fp,格式字符串,输出列表);

返值:成功,返回I/O的个数;出错或文件尾,返回EOF 由于输入输出时要进行ASCII码和二进制形式的转换,费时较多。

fscanf( fp,“%d,%f”,&i,&t);     /*若文件中有 3 , 4.5  ,则将3读出送入 i , 4.5读出送入t*/

fprintf(fp,“%d,%6.2f”,i,t);     /*将i和t按 %d, %6.2f 格式写入到 fp文件*/

void save()
{  
   FILE *fp;
   int  i;
   if((fp=fopen("d:\\stu_list","w"))==NULL)
   { 
        printf("cannot open file\n");
        return;
   }
   for(i=0;i<SIZE;i++)
      fprintf(fp,"%s %d %d %s",stud[i].name,
            stud[i].num,stud[i].age,stud[i].addr);
   fclose(fp);
}
void display()
{ 
   FILE *fp;
   int  i;
   if((fp=fopen("d:\\stu_list","r"))==NULL)
   { 
       printf("cannot open file\n");   return;}
       for(i=0;i<SIZE;i++)
       { 
           fscanf(fp,"%s %d %d %s",stud[i].name,
                   stud[i].num,stud[i].age,stud[i].addr);         
           printf("%-10s %4d %4d %-15s\n",stud[i].name,
                   stud[i].num,stud[i].age,stud[i].addr);
       }
       fclose(fp);
    }
}

其它读写函数

6.  putw和getw函数

作用:以二进制形式,对磁盘文件读写一个 int 型的整数,2个字节。

返值:成功:所写的整数值;失败:EOF。            

如:putw(10,fp);                  

 i=getw(fp);

7.fgets 和fputs函数

形式:

fgets(str,n,fp);   (str字符数组,n-1个字符)                

fputs(字符串,fp); ("\0"不输出)

作用:从fp指向的文件读/写一个字符串

返值: fgets正常时返回字符串的首地址;出错或文件尾,NULL fputs正常时返回写入的最后一个字符;出错为EOF

例   从键盘读入字符串存入文件,再从文件读回显示

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{ 
	FILE  *fp;
	char  string[81];
	if((fp=fopen("1.txt","w"))==NULL)
	{ 
		printf("cann't open file");
		exit(0); 
	}
	while(strlen(gets(string))>0)
	{ 
		fputs(string,fp);
		fputs("\n",fp); 
	}
	fclose(fp);
	if((fp=fopen("1.txt","r"))==NULL)
	{ 
		printf("cann't open file");
		exit(0); 
	}
	while(fgets(string,81,fp)!=NULL)
	   fputs(string,stdout);
	fclose(fp); 
}

10.5  文件的定位

几个概念

文件位置指针-----指向当前读写位置的指针,具体位置由文件打开方式确定。

  • “r”“w”:指向文件头
  • “a”:指向文件尾

读写方式

  • 顺序读写:位置指针按字节位置顺序移动。
  • 随机读写:位置指针按需要移动到任意位置。

1.rewind函数

函数原型:  void  rewind(FILE  *fp)

功能:重置文件位置指针到文件开头

返值:无

例 对一个磁盘文件进行显示和复制两次操作

#include <stdio.h>
void main()
{ 
   FILE *fp1,*fp2;
   fp1=fopen("c:\\tc\\user\\ch12_4.c","r");
   fp2=fopen("d:\\tc\\user\\ch12_41.c","w");
   while(!feof(fp1))  
       putchar(getc(fp1));
   rewind(fp1);
   while(!feof(fp1))  
       putc(getc(fp1),fp2);
   fclose(fp1);   
   fclose(fp2);
}

2.fseek函数和随机读写

调用形式:fseek(文件类型指针,位移量,起始点)

功能:改变文件位置指针的位置

返值:成功,返回0;失败,返回非0值

例  文件内存有10个学生数据,将单数学生数据输入计算机并在屏幕上显示

#include <stdlid.h>
#include <stdio.h>
struct student_type
{ 
   char name[10];
   int num;
   int age;
   char sex;
}stud[10];

void main()
{ 
   FILE *fp;
   int  i;
   if((fp=fopen("stud_dat","rb"))==NULL)
   { 
       printf("cannot 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);
}

3.ftell函数

函数原型:  long  ftell(FILE  *fp)

功能:得到流式文件中位置指针当前位置(用相对于文件开头的位移量表示)

返值:返回当前位置指针位置;失败,返回-1L

//例  求文件长度
#include"stdio.h"
void main()
{ 
	FILE *fp;
	char filename[80];
	long length;
	gets(filename);
	fp=fopen(filename,"rb");
	if(fp==NULL)
	   printf("file not found!\n");
	else
	{ 
		fseek(fp,0L,SEEK_END);
	    length=ftell(fp);
	    printf("Length of File is %1d bytes\n",length);
	    fclose(fp);  
	}
}

10.6  出错的检测

1.ferror函数:

  • 测试文件是否出现错误
  • 调用形式: ferror(fp);
  • 返值:未出错,0;出错,非0
  • 说明 每次调用文件输入输出函数,均产生一个新的ferror函数值,所以应及时测试 fopen打开文件时,ferror函数初值自动置为0

2.clearerr函数

调用形式: clearerr(fp);

功能:使文件错误标志置为0,无返值。

说明:出错后,错误标志一直保留,直到对同一文件调clearerr(fp)或rewind或任何其它一个输入输出函数

例   ferror()与clearerr()举例
#include <stdio.h>
int  main(void)
{ FILE *stream;
   stream = fopen("DUMMY.FIL", "w");
   getc(stream);
   if (ferror(stream))
     { printf("Error reading from DUMMY.FIL\n");
        clearerr(stream);
     }
   if(!ferror(stream))
       printf("Error indicator cleared!");
   fclose(stream);
   return 0;
}

10.7  文件输入输出小结

  1. 使用文件时,首先要定义一个文件指针:
  2. FILE *fp;然后通过该指针来操作相应的文件;
  3. 通过fopen这个函数,使文件指针fp和相应的文件建立了联系,通过fclose函数将fp和文件的联系切断;
  4. 文件可以以文本的方式打开(默认或“t”),也可以以二进制方式打开(“b”);
  5. 如果以一次一个字符的方式处理文件,需要用fgetc或者fputc函数;
  6. 如果以一次一行的方式处理文件,可以用函数fgets或者fputs;
  7. 如果以一次一个结构体的方式处理文件,可以用函数fread和fwrite(多为二进制文件);
  8. fscanf和fprintf函数使用很广泛,应重点掌握。

本文笔记来自C程序设计谭浩强PPT,我是热爱学习的呵呵哒!

如果您觉得写得不错,点个赞呀~

猜你喜欢

转载自blog.csdn.net/weixin_41987016/article/details/105879508