对文件的输入输出

一曲冷凌霜 提交于 2020-01-22 02:40:58

1. 什么是文件

文件分为两种, 程序文件 数据文件

  1. 程序文件。包括源文件(后缀为.c)、目标文件(后缀为.obj)、可执行文件(后缀为.exe)等。这种文件的内容是可执行代码。
  2. 数据文件。如一批学生的成绩数据等。

2. 打开与关闭文件

fopen函数打开数据文件,fclose函数关闭数据文件。

  1. 通常将fopen函数的返回值赋给一个指向文件的指针变量
    FILE *fp ; // 定义一个指向文件的指针变量
    fp = fopen("a1", "r");

  2. fclose 函数关闭数据文件
    fclose(fp);

3. 顺序读写数据文件

怎样向文件读写字符

栗1:
  从键盘输入一些字符,逐个把它们送到磁盘上去,直到用户输入一个"#"为止

#include <stdlib.h>
#include <stdio.h>
int main()
  {FILE *fp;
   char ch,filename[10];
   printf("请输入所用的文件名:");
   scanf("%s",filename);
   if((fp=fopen(filename,"w"))==NULL)   // 打开输出文件并使fp指向此文件 
	  {
       printf("无法打开此文件\n");       // 如果打开时出错,就输出"打不开"的信息  
       exit(0);                        // 终止程序
       }
   ch=getchar( );                    // 此语句用来接收在执行scanf语句时最后输入的回车符  
   printf("请输入一个准备存储到磁盘的字符串(以#结束):");
   ch=getchar( );                   // 接收从键盘输入的第一个字符 
   while(ch!='#')                   // 当输入'#'时结束循环  
	{
	  fputc(ch,fp);                 // 向磁盘文件输出一个字符  
      putchar(ch);                  // 将输出的字符显示在屏幕上  
	  ch=getchar();                 // 再接收从键盘输入的一个字符  
 
	 }
   fclose(fp);                      // 关闭文件  
   putchar(10);                     // 向屏幕输出一个换行符,换行符的ASCII代码为10 
   return 0;
  }

在这里插入图片描述
栗2:
  将一个磁盘文件中的信息复制到另一个磁盘文件中。 今要求将上例建立的file1.dat文件中的内容复制到另一个磁盘文件file2.dat中。

#include <stdio.h>
#include <stdlib.h>
int main( )
  {FILE *in,*out;
   char  ch,infile[10],outfile[10];     // 定义两个字符数组,分别存放两个文件名  
   printf("输入读入文件的名字:");
   scanf("%s",infile);                  // 输入一个输入文件的名字  
   printf("输入输出文件的名字:");
   scanf("%s",outfile);                 // 输入一个输出文件的名字  
   if((in=fopen(infile,"r"))==NULL)     // 打开输入文件  
      {printf("无法打开此文件\n");
       exit(0);
      }
   if((out=fopen(outfile,"w"))==NULL)   // 打开输出文件  
     {printf("无法打开此文件\n");
      exit(0);
     }
   while(!feof(in))                    // 如果未遇到输入文件的结束标志  
     {ch=fgetc(in);                    // 从输入文件读入一个字符,暂放在变量ch中 
	  fputc(ch,out);                   // 将ch写到输出文件中  
      putchar(ch);                     // 将ch显示在屏幕上  
     }
   putchar(10);                        // 显示完全部字符后换行  
   fclose(in);                         // 关闭输入文件  
   fclose(out);                        // 关闭输出文件  
   return 0;
  }

在这里插入图片描述
4. 向文件中读写一个字符串

函数名 调用形式 功能 返回值
fgets fgets(str,n,fp) 从fp指向的文件读入一个长度为 (n-1) 的字符串,并在最后加一个‘\0’字符, 然后把这 n 个字符存放到字符数组 str中 读成功,返回地址str,失败则返回NULL
fputs fputs(str,fp) 把str所指向的字符串写到文件指针变量 fp 所指向的文件中 输出成功,返回0;否则返回非0值

栗3:
  从键盘读入若干字符串,对它们按字母大小的顺序排序,然后把排好序的字符串送到磁盘文件中保存

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(){
	FILE *fp;
	char s[3][20],temp[20],filename[20];
	int i,j,k,n=3;
	
	for(i=0;i<n;i++){
		printf("请输入第%d个字符串: ",i+1);
		gets(s[i]);
	}
	
	for(i=0;i<n-1;i++){
		k = i;
		for(j=i+1;j<n;j++)
			if(strcmp(s[k],s[j])<0)	k = j;
		
		if(k!=i){
			strcpy(temp,s[i]);
			strcpy(s[i],s[k]);
			strcpy(s[k],temp);
		}
	}
	
	printf("请输入磁盘文件名:");
	scanf("%s",filename);
	 // if((fp=fopen("D:\\CC\\string.bat","w"))==NULL)指定其他磁盘文件注意路径格式 
	if((fp=fopen(filename,"w"))==NULL){
		printf("打开文件失败!");
		exit(0);
	}
	
	printf("\n结果为:\n");
	for(i=0;i<n;i++){
		fputs(s[i],fp);
		fputs("\n",fp);
		printf("%s\n",s[i]);
	}
	return 0;
} 

在这里插入图片描述
5. 用格式化的方式读写文件

  与printfscanf 明显的不同是 fprintffscanf 函数的读写对象不是终端而是文件,它们一般的调用方式为:

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

例如:
   1. fprintf(fp,"%d, %6.2f", i, f);
   它的作用是将int 型变量ifloat 型变量 f 的值按 %d%6.2f 的格式输出到fp指向的文件中。
   2. fscanf(fp,"%d, %f", &i, &f);
   磁盘文件上如果有 "3, 4.5",则从磁盘文件中读取整数3送给整型变量i,读取实数4.5送给float型变量f

6. 用二进制方式向文件读写一组数据

它们一般的调用方式为:

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

其中,
   buffer: 是一个地址。对fread来说,它是用来存放从数据文件存储区的地址。对fwrite来说,把此地址开始的存储区的数据向文件输出。
   size: 要读写的字节数。
   count: 要读写多少个数据项(每个数据项的长度为size)。
   fp: FILE 类型的指针。

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

#include<stdio.h>
#define N 3

struct student
{
	char name[10];
	int num;
	int age;
}stud[N];     //定义全局结构体数组stud,包含3个学生数据

//对所要调用的函数进行声明
void input();
void save();
void readFile();
int main()
{
	printf("please input student's message:\n");
	input();
	save();
	readFile();
	return 0;
}
/*
 *函数名称:input()
 *函数功能:给stud数组中的数据赋值
 *返回值:void
*/ 
void input()
{
	for(int i=0;i<N;i++)
	{
		scanf("%s %d %d",&stud[i].name,&stud[i].num,&stud[i].age);
	}
	printf("\n");
}
/*
 *函数名称:readFile()
 *函数功能:从键盘上读取输入的学生数据
 *返回值:void
*/ 
void readFile()
{
	FILE *p;
	int i;
	if((p=fopen("stu_dat","rb"))==NULL)
	{
		printf("cannot open the file\n");
		return;
	}
	for(i=0; i<N; i++)
	{
		fread(&stud[i],sizeof(struct student),1,p);
		printf("%-10s %4d %4d\n",stud[i].name,stud[i].age,stud[i].num);
	}
	fclose(p);
	return;
}
/*
 *函数名称:save()
 *函数功能:向文件输出学生的数据
 *返回值:void
*/ 
void save()
{
	int i;
	FILE *p;
	if((p=fopen("stu_dat","wb"))==NULL)//打开输出文件
	{
		printf("cannot open file\n");
		return;
	}
	for(i=0;i<N;i++)
	{
		if(fwrite(&stud[i],sizeof(struct student),1,p)!=1)
		{
			printf("file write error\n");
		}		
	}	
	fclose(p);
}

在这里插入图片描述
7. 随机读写数据文件

   例如文件中有1000个数据,若只查第1000个数据,必须先逐个读入前面999个数据,才能读入第1000个数据。

1). 文件位置标记及其定位

在这里插入图片描述

2). 文件位置标记的定位

1. rewind 函数使文件位置标记重新返回文件的开头,此函数没有返回值

  有一个磁盘文件,内有一些信息。要求第1次将它的内容显示在屏幕上,第2次把它复制到另一份文件上。

#include<stdio.h>
int main()
{
	FILE *fp1,*fp2;
	fp1=fopen("file1.dat","r");              // 打开输入文件  
	fp2=fopen("file2.dat","w");              // 打开输出文件  
	while(!feof(fp1)) putchar(getc(fp1));    // 逐个读入字符并输出到屏幕,feof函数是判断文件位置标记是否到文件末尾
	putchar(10);                             // 输出一个换行 
	rewind(fp1);                             // 使文件位置指示器返回文件头  
	while(!feof(fp1)) putc(getc(fp1),fp2);   // 从文件头重新逐个读字符,输出到file2文件
 
	fclose(fp1);fclose(fp2);
	return 0;
}

2. fseek 函数改变文件位置标记

fseek函数的调用方式为:

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

  "位移量"以"起始点"为基点,向前移动的字节数。位移量应是long型数据 (在数字的末尾加上一个字母L,就表示是long型)。

fseek 函数一般用于二进制文件。下面是 fseek 函数调用的几个例子:

fseek(fp, 100L, 0);  // 将文件位置标记向前移动离文件开头100个字节处
fseek(fp, 50L, 1);   // 将文件位置标记向前移动离当前位置 50个字节处
fseek(fp, -10L, 2);  // 将文件位置标记从文件末尾处向后退 10 个字节

3. ftell 函数的作用是得到文件位置标记的当前位置

i = ftell(fp);      // 变量 i 存放文件当前位置
if (i == -1L)  printf("error\n");    // 如果调用函数时出错,输出"error"

8. 随机读写

  有了 rewind 和 fseek 函数,就可以实现随机读写了。

  在磁盘文件上存入10个学生的数据。要求将1,3,5,7,9个学生数据输入计算机,并在屏幕上显示出来

#include<stdio.h>
#include <stdlib.h>

struct Student_type //学生数据类型
{ 
	char name[10];
	int num;
	int age;
	char addr[15];
}stud[10];

int main()
{ 
	int i;
	FILE *fp;

	if((fp=fopen("file1.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("%-10s %4d %4d %-15s\n",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
													//在屏幕输出

}

fclose(fp);
return 0;
}

9. 文件读写的出错检测

C提供一些函数用来检查输入输出函数调用时可能出现的错误。

1). ferror函数

它的一般调用形式为: ferror(fp);

说明:

  在调用各种输入输出函数(如putc,getc,fread,fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。

  如果ferror返回值为0(假),表示未出错;如果返回一个非零值,表示出错。

2). clearerr函数

说明:
  clearerr 的作用是使文件出错标志和文件结束标志置为0。

  假设在调用一个输入输出函数时出现错误,ferror 函数值为一个非零值。应该立即调用clearerr(fp),使ferror(fp)的值变成0,以便再进行下一次的检测。

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

:对同一个文件每一次调用输入输出函数,都会产生一个新的ferror函数值,因此,应当在调用一个输入输出函数后立即检查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。

https://blog.csdn.net/weixin_30883777/article/details/96493618

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!