文件_文件类型 - CSDN
精华内容
参与话题
  • C语言对文件的操作

    万次阅读 多人点赞 2018-12-20 23:08:52
    前言在谭浩强的C语言设计的第10张讲了有关文件的知识, 以往我们写的C程序的数据都是由键盘输入的 现在我们要对文件进行操作。 文件是操作系统的基本单位。是我们专业领域的重要的一部分。 就拿我们的编译器来说...

    前言在谭浩强的C语言设计的第10张讲了有关文件的知识,
    以往我们写的C程序的数据都是由键盘输入的
    现在我们要对文件进行操作。

    文件是操作系统的基本单位。是我们专业领域的重要的一部分。
    就拿我们的编译器来说,我们写了一个程序,成功的运行了,编译系统会主动的生成3个文件如下图
    在这里插入图片描述

    它们分别是源程序文件.c
    目标文件.o
    可执行文件.exe

    在实际的情况下,常常要把一些数据输出到磁盘上保存起来,在需要时送入内存之中这就需要我们用到磁盘文件。

    1.文件名
    一个文件要有一个唯一的文件标识以便识别和引用,分别为
    1.路径(用来找到文件)
    2.名称(识别是什么)
    3.后缀(文件的格式或属性)

    在这里插入图片描述

    2.文件的分类
    书上将文件分成两类,分别是
    ASCII文件二进制文件
    1.ASCII文件我们在刚刚接触c语言时就了解了ASCII标,每个特定的数代表一个字符,那么将字符形式的文件就是ASCII文件,也称为文本文件,每个字节存放一个字符的ASCII值。
    2.二进制文件
    数据在内存中是以二进制形式存储的(因为CPU只认识0和1),如果不加转换的输出到外存,就是二进制文件。也称之为映像文件
    (因为从二进制转换到ASCII需要一定的时间,占的空间也更多,加之二进制文件的实用优点,我们生活中常用二进制的文件。)

    3.缓冲区概念
    我们都知道,在计算机的存储设备中,CPU的缓存速度是最快的,其次是显卡的显存,DDR5的显存早就已经普及,并有被淘汰之势,再次是内存,就在这几年DDR4的内存才开始广泛的使用,最慢的就是我们的硬盘(磁盘),机械硬盘的转速很慢,最快的速度也只有200多MB一秒,尽管我们现在普遍用上了固态硬盘,还是M.2协议的,但是和内存的差距依旧很大。因为两者的差距太大,就必须在数据写入磁盘时就有必要在内存中开辟一片缓冲区(所以缓冲区不是什么高大上的东西)

    4.文件类型指针
    回顾前面的知识,指针必须要有基类型(指向),如int p,floatp…。
    那么顾名思义文件指针就是指向文件的,其实文件在C语言中是,一种结构体
    也就是和结构体指针是一样的。
    以下是文件结构体的定义,结构体的名称为FILE。

    tpyedef struct
    {  short level;      //缓冲区满或空的程度
    
       unsigned flags;   //文件状态标志
       
       char fd;          //文件描述符
       
       unsigned char hold;  //如缓冲区无内容不读取字符
       
       short bsize;            //缓冲区的大小
       
       unsigned char*buffer;     //数据缓冲区的位置
       
       unsigned char*curp;      //文件位置标记指针当前的指向
       
       unsigned istemp;        //临时文件指示器
       
       short token;         //用于有效性检查
       }FILE
       //这是TC2.0中的定义
    
    #ifndef _FILE_DEFINED
    struct _iobuf {
    
         char *_ptr; //文件输入的下一个位置
                int   _cnt;  //当前缓冲区的相对位置
                char *_base;  //指基础位置(即是文件的其始位置) 
                int   _flag;  //文件标志
                int   _file;   //文件的有效性验证
                int   _charbuf;  //检查缓冲区状况,如果无缓冲区则不读取
                int   _bufsiz;   //缓冲区大小
                char *_tmpfname;  //临时文件名
            };
    typedef struct _iobuf FILE;
    #define _FILE_DEFINED
    #endif  //这是VC6。0里定义
    

    当然我们不必去深究其中的作用(会写标准库定义的人不知道比我们高到哪里去了)
    但要稍微了解一下

    下面介绍关于文件的函数
    1.打开与关闭文件函数
    fopen 打开文件函数 (成功打开后指向该流的文件指针就会被返回,失败返回NULL)
    fclose 关闭文件函数
    引用方法

    fopen(文件名,使用文件方式)//文件名是一个字符串,使用方式需要加双引号,
    

    为了使文件指针与文件建立联系我们要将函数返回的指针给我们的文件指针
    像这样

    FILE*fp;
    fp = fopen("test.txt","r");//以读的方式打开默认路径下一个叫test的文本文件
    

    可以说这样就将fp指向了test这个文件。
    既然文件的使用方式,我们就要全面的了解

    文件使用方式 含义 如果指定的文件不存在
    r(只读) 输入数据,打开一个已存在文本文件 出错
    w(只写) 输出数据,打开一个文本文件 建立一个新文件
    a(追加) 向文本文件尾添加数据 出错
    rb(只读) 输入数据,打开一个2进制文件 出错
    wb(只写) 输出数据,打开一个2进制文件 建立新文件
    r+(读写) 读写,文本文件 出错
    w+(读写) 读写,文本文件 建立新文件
    a+(读写) 读写,文本文件 出错
    rb+(读写) 读写,二进制文件 出错
    wb+(读写) 读写,二进制文件 建立新文件
    ab+(读写) 读写二进制文件 出错

    这里我们来用一个小程序演示一下
    我现在编译器默认路径下建立一个空的文本文件test
    在这里插入图片描述

    #include <stdio.h>
    int main()
    {
         FILE*p; //设置一个文件指针
    
         char ch; //定义一个字符变量
    
         if((p=fopen("test.txt","w"))==NULL) //打开一个叫test的文本文件,以只写的方式,当   出错时,即返回值为NULL时,输出错误信息
         {
                printf("ERROR");
    
               exit(0); //关闭所有文件,终止正在执行的程序
          }
    
          for(;ch!='\n';) //输入ch知道输入空格。
          {
                scanf("%c",&ch);
                 fputc(ch,p); //将字符ch写入p所指向的文件
          } 
    fclose(p);//关闭文件
    }
    

    在这里插入图片描述我们再到默认路径打开test.txt。

    在这里插入图片描述可以看到我们在键盘里输出的Merry Christmas已经被写入了test之中

    下面我们来读取这个文件里的信息
    我们只需要将程序稍微修改一下就可以

    #include <stdio.h>
    int main()
    {
    	FILE*p;
    	
    	char ch;
    	
    	if((p=fopen("test.txt","r"))==NULL)  //以只读的方式打开test。
    	{
    		printf("ERROR");
    		
    		exit(0);
    	}
    	
    	for(;ch!='\n';)
    	{
    		ch=fgetc(p);   //ch得到p所指文件中的每一个字符
    		putchar(ch);     //将得到的字符输出到屏幕
    	}
    	
    
    	fclose(p);	//关闭文件
    }
    

    下面是截图
    在这里插入图片描述

    值得注意的是,在我们向文件写入的时候会将原有的内容清空再进行写入
    请看我们再对test进行写入
    这次我输入了happy
    在这里插入图片描述
    再到默认路径下打开text文件
    在这里插入图片描述

    可以看到我们的Merry Christmas被清除了并用我们的happy写入了文件
    如果要对文本文件 进行写入并保留原有内容,就要用追加的方式进行

    	if((p=fopen("test.txt","a"))==NULL) //只需将w改为a即可
    

    下面我们再进行写入
    在这里插入图片描述
    再打开test文件
    在这里插入图片描述

    5.顺序读写数据文件

    1.读写字符函数
    读字符 fgetc

    fegrtc(文件指针)   //从指针所指向的文件中读入一个字符
    

    写字符fputc

    fputc(ch,fp)    //把字符变量ch写到fp所指向的文件中去
    

    我们在上一个例子中就使用了这俩个函数,为了有更深刻的印象。
    我以一个文件复制的程序来中举例
    下面是源码

    #include <stdio.h>
    int main()
    {
    	FILE*p1,*p2;    //设置2个文件指针
    	
    	char filename[30],filename1[30],ch;  //设置2个字符数组用来输入文件名用
    	
    	printf("请输入要复制的文件名\n"); 
    	
    	gets(filename);      //输入文件名
    	
    	printf("请输入复制后的文件名:\n");
    	
    	gets(filename1);     //输入文件名
    	
    	if((p1=fopen(filename,"rb"))==NULL)  //打开被复制的文件
    	{
    		printf("ERROR");
    		
    		exit(0);
    	}
    	if((p2=fopen(filename1,"wb"))==NULL) //写入要复制的文件名
    	{
    		printf("ERROR");
    		
    		exit(0);
    	}
    	
    	while(!feof(p1))    //用一个检查文件是否结束的函数来判断
    	{
    		ch=fgetc(p1);   //读出每一个p1指向的文件中的字节,把ch写入到p2指向的文件中去,如果没有p2文件,则会建立一个以filename1字符数组命名的文件
    		
    		fputc(ch,p2);
    	} 
    	
    	printf("复制成功"); 
    	
    	fclose(p1);   //用完之后,为了避免不必要的操作干扰读写,要关闭文件,即断掉文件指针与文件的联系
    	fclose(p2);
    	
    	
    	
    }
    

    下面是运行效果,我的默认路径中有一张名为23.jpg的图片文件
    在这里插入图片描述运行程序
    写入如下
    在这里插入图片描述再去查看默认路径
    就多了一张叫jaychou的jpg图片
    在这里插入图片描述下面就要介绍检测文件是否介绍的函数
    feof(end of file)

    feof(文件指针)   //当文件结束时返回非0值,当文件未结束时返回0
    

    再看刚才的循环语句

    while(!feof(fp))//当返回值为0的时候执行循环,返回值非0的时候就结束循环
    

    当然我们也可以用这个程序来复制文本文件
    在这里插入图片描述在这里插入图片描述

    当然对于文本文件文件可以不用二进制的方式处理
    我们也可以把刚才的循环语句换成如下

    while(!(ch=fgetc(fp))==EOF)      //我们的EOF和NULL一样都是标准库里的宏定义EOF就是-1,NULL代表0
    

    那么这个-1又代表了什么
    文件的所有有效字符后有一个文件尾标志,当读完全部的字符后,文件读写位置标记就会指向最后一个字符的后面的结束字节(里面存放了-1),如果再读取就会读出-1
    在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~127,不可能出现-1,因此可以用EOF作为文件结束标志。

    WARNING二进制文件因为是以二进制形式保存的所以不能以字符的方式来存取的,所以不应用刚才的方式对二进制文件进行写入。

    同样
    我们也有字符串的读写文件

    函数名 调用形式 功能 返回值
    fgets fgets(str,n,fp) 从fp指向的文件读入一个长度为n-1的字符串,存放到字符数组str中去 成功返回地址str,失败返回NULL
    fputs fputs(str,fp)) 把str所指向的字符串写入fp所指向的文件中 成功返回0,失败返回非零

    下面来举个例子
    现在test中写如下内容
    在这里插入图片描述我们用fgets函数读取出来并输出上面的文字

    #include <stdio.h>
    #define LEN 40
    int main()
    {
    	FILE*fp;
    	
    	char filename[LEN],string[30]; //定义一个字符数组来存储文件里的信息
    	
    	printf("请输入要打开的文件名");
    	
    	gets(filename);
    	
    	if((fp=fopen(filename,"r"))==NULL)   //以只读的方式打开文件打开文件
    	{
    		printf("ERROR");
    		exit(0);
    	} 
    	
    	fgets(string,20,fp);  //将fp所指的文件中的20字符读取给字符串string
    	
    	fclose(fp);   //关闭文件
    	
    	puts(string);  //以字符串形式输出string
    	
    }
    

    在这里插入图片描述

    6.用格式化的方式读写文本文件
    在我们以前的输出输入之中,常用scanf和printf函数,我们的格式化读写函数和他们类似

    名称 引用方式
    fprintf fprintf(文件指针,格式字符串,输出列表)
    fscanf fscanf(文件指针,格式字符串,输入列表)
    #include <stdio.h>
    int main()
    {
    	int i=3;float j=4.567;char string[20];
    	
    	FILE*fp;
    	
    	if((fp=fopen("test.txt","r+"))==NULL)   //以读写的方式打开test
    	{
    		printf("ERROR");
    		exit(0);
    	}
    	
    	fscanf(fp,"%s",string);  把其中的字符串写入字符数组string中
    	
    	puts(string); //输出由文件中写入的字符串
    	
    	
    	fprintf(fp,"%3d,%6.4f",i,j);  //以%3d,%6.4的格式输入整形变量i和浮点型变量j
    	
    	fclose(fp);   //关闭文件
    	
    } 
    

    在这里插入图片描述
    再去默认路径中打开test文件
    在这里插入图片描述
    7.用二进制方式向文件读写一组数据

    其实我们上面的复制图片的例子也是对二进制文件的读写,在这里有一组专门的二进制文件读写函数
    分别是
    fread
    fwrite

    名称 引用方式
    fread fread(buffer,size,count,fp)
    fwrite fwrite(buffer,size,count,fp)

    也被称为数据块读写

    函数原型size_t fread ( void *buffer, size_t size, size_t count, FILE *stream)

    参 数
    buffer
    用于接收数据的内存地址(是一个指针,无论输出输入都是首地址)
    size
    要读的每个数据项的字节数,单位是字节
    count
    要读count个数据项,每个数据项size个字节.
    stream
    文件指针

    数据块读写多用于结构体变量的读写(因为结构体所占的字符数是不规则的)
    下面举一个例子

    #include <stdio.h>
    #define LEN 15   //结构体中字符串的长度
    #define NUM 8    //要输入数据学生的个数
    struct Student    //定义学生结构体
    {
    	char name[LEN];
    	
    	int num;
    	
    	int age;
    	
    	char add[LEN];
    }Stud[NUM];      //将数据先存放在结构体数组之中
    int main()
    {
    	FILE*fp;
    	
    	int i;
    	
    	if((fp=fopen("stduent","wb"))==NULL)  //建立一个叫student的文件以二进制形式进行打开进行写入操作,
    	{
    		printf("ERROR");
    		
    		exit(0);
    	}
    	
    	printf("请输入学生数据\n");
    	
    	for(i=0;i<NUM;i++)   //
    	{
    		scanf("%s%d%d%s",&Stud[i].name,&Stud[i].num,&Stud[i].age,&Stud[i].add);//输入学生数据信息
    	}
    	
    	for(i=0;i<NUM;i++)
    	{
    		if(fwrite(&Stud[i],sizeof(struct Student),1,fp)!=1)//每次写一个结构体变量所占的字节,将输入的数据写入文件
    		{
    			printf("write error");
    		}
    	}
    	
    	fclose(fp);	//关闭文件
    }
    

    完成输入如图
    在这里插入图片描述当我们去默认路径找到student文件,发现并不是文本文件,用文本文本的格式打开会看见二进制的源码转化出的乱码
    在这里插入图片描述我们再改变一下以上的代码,将student的文件中的学生数据读取出来

    按照上面的输入稍微修改一下即可
    下面是代码

    #include <stdio.h>
    #define LEN 15
    #define NUM 8 
    struct Student
    {
    	char name[LEN];
    	
    	int num;
    	
    	int age;
    	
    	char add[LEN];
    }Stud[NUM];
    int main()
    {
    	FILE*fp;
    	
    	int i;
    	
    	if((fp=fopen("student","rb"))==NULL)  //以二进制的方式读取
    	{
    		printf("ERROR");
    		
    		exit(0);
    	}
    	
    	printf("姓名 学号 年龄 地址\n");
    	
    	
    	
    	for(i=0;i<NUM;i++)   //将数据每次一个结构体变量所占字节的个数的数据赋给结构体变量
    	{
    		if(fread(&Stud[i],sizeof(struct Student),1,fp)!=1)
    		{
    			printf("read error");
    		}
    	}
    	
    	for(i=0;i<NUM;i++)  //输出结构体变量的各个成员,输出数据
    	{
    		printf("%-10s%4d%4d%-15s",Stud[i].name,Stud[i].num,Stud[i].age,Stud[i].add);
    		printf("\n");
    	}
    	
    	fclose(fp);	//关闭文件
    }
    

    下面是运行截图
    在这里插入图片描述不用从键盘输入数据,将文件中的数据读取出来

    PS(当文件不在编译器默认的路径时,要在文件名初加上文件的路径,
    若一个文件为D:\data\student,我们要输入它的路径如下
    D:\data\student因为只是一个反斜杠的话会被和后面的字符被认为是转义字符处理,
    这也是我们的老师在我们刚学C语言时就教过的)

    8.随机读写数据文件

    1.文件位置标记即其定位

    文件位置标记其实是一个文件中的一个指针
    在我们的顺序读写当中,都是一个字符一个字符的读出有写入
    没有出现跳跃的情况,
    但在实际使用的过程中,我们不许要每次都要把文件全部都读一遍
    只需要稍微的改动某些数据,
    下面由本人这个灵魂画师来画一个图演示一下
    在这里插入图片描述
    文件位置标记的定位

    rewind 功能是将文件内部的指针重新指向一个文件的开头

    rewind(文件指针);
    

    现在把上面的代码改一下

    #include <stdio.h>
    #define LEN 15
    #define NUM 8 
    struct Student
    {
    	char name[LEN];
    	
    	int num;
    	
    	int age;
    	
    	char add[LEN];
    }Stud[NUM];
    int main()
    {
    	FILE*fp,*fp1;
    	
    	int i;
    	
    	if((fp=fopen("student","rb"))==NULL)
    	{
    		printf("ERROR");
    		
    		exit(0);
    	}
    	if((fp1=fopen("CSDN","wb"))==NULL)   //以写入的方式打开一个文件
    	{
    		printf("ERROR");
    		
    		exit(0);
    	}
    	
    	printf("姓名     学号   年龄     地址\n");
    	
    	
    	
    	for(i=0;i<NUM;i++)    //把文件中的数据读入结构体数组的元素
    	{
    		if(fread(&Stud[i],sizeof(struct Student),1,fp)!=1)
    		{
    			printf("read error");
    		}
    	}
    	
    	rewind(fp);   //重置文件指针
    	
    	for(i=0;i<NUM;i++)  //写入新的文件中
    	{
    		if(fwrite(&Stud[i],sizeof(struct Student),1,fp1)!=1)
    		{
    			printf("read error");
    		}
    	}
    	
    	for(i=0;i<NUM;i++)  //输出文件数据
    	{
    		printf("%-10s%4d%4d%15s",Stud[i].name,Stud[i].num,Stud[i].age,Stud[i].add);
    		printf("\n");
    	}
    	
    	fclose(fp);	
    	fclose(fp1);
    }
    

    运行如前面的图一样,默认路径中出现了一个名为CSDN的文件,里面存放着学生的数据

    fseek函数,文件指针位置函数
    引用方法为

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

    起始点有3种情况,分别是0,1,2
    如表

    起始点 名字 用数字代表
    文件开始位置 SEEK_SET 0
    文件当前位置 SEEK_CUR 1
    文件末尾位置 SEEK_END 2

    位移量是long形数据要在结尾加上L

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

    在上面的代码出修改一下

    	for(i=0;i<NUM;i+=2)
    	{
    		fseek(fp,i*sizeof(struct Student),0);//跳过每次移动2个结构体所占的字节
    		
    		printf("%-10s%4d%4d%15s",Stud[i].name,Stud[i].num,Stud[i].age,Stud[i].add);
    		printf("\n");
    	}
    

    我们就实现了只输出部分的数据
    在这里插入图片描述ferror函数
    在调用各种输入输出函数(如 putc.getc.fread.fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。 它的一般调用形式为 ferror(fp);如果ferror返回值为0(假),表示未出错。如果返回一个非零值,表示出错。应该注意,对同一个文件 每一次调用输入输出函数,均产生一个新的ferror函 数值,因此,应当在调用一个输入输出函数后立即检 查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。
    clearerr
    clearerr的作用是使文件错误标志和文件结束标志置为0.假设在调用一个输入输出函数时出现了错误,ferror函数值为一个非零值。在调用clearerr(fp)后,ferror(fp)的值变为0。
    只要出现错误标志,就一直保留,直到对同一文件调用clearerr函数或rewind函数,或任何一个输入输出函数。

    感想:这是我的C语言博客的结束篇,在这2个多月的学习中,有困难也有喜悦,从一个小白,渐渐打开编程的一角,C语言交给我的思想,会帮我开起我的程序人生。
    farewell C

    展开全文
  • 文件的概念

    千次阅读 2018-02-11 11:11:49
    ---------文件的定义:  文件是操作系统中的一个重要概念。文件是以计算机硬盘为载体存储在计算机上的信息集合,文件可以是文本文档、图片、程序,等等。在系统运行时,  计算机以进程为基本单位进行资源的调度...

    ---------文件的定义:

                文件是操作系统中的一个重要概念。文件是以计算机硬盘为载体存储在计算机上的信息集合,文件可以是文本文档、图片、程序,等等。在系统运行时,

          计算机以进程为基本单位进行资源的调度和分配而在用户进行的输入、输出中,则以文件为基本单位。大多数应用程序的输入都是通过文件来实现的,

          其输出也保存在文件中,以便信息的长期存储及将来的访问。当用户将文件用于应用程序的输入、输出时,还希望可以访问文件、修改文件和保存文件等,实现

          文件的维护管理,这就需要系统提供一个文件管理系统,操作系统的文件系统就是用于实现用户的这些管理要求。

                从用户的角度看,文件系统是操作系统的重要部分之一。用户关心的是如何命名、分类和查找文件,如何保证文件数据的安全性以及对文件可以进行哪些操作

          等。而对其中的细节,如文件如何存储在辅存上、如何管理文件辅存区域等关心甚少。

                文件系统提供了与二级存储相关的资源的抽象,让用户能在不了解文件的各种属性、文件存储介质的特征以及文件在存储介质上的具体位置等情况下,方便快捷

          地使用文件。

                用户通过文件系统建立文件,提供应用程序的输入、输出,对资源进行管理。首先了解文件的结构,我们通过自底向上的方式来定义:

                (1)、数据项。数据项是文件系统中最低级的数据组织形式,可分为以下两种类型:

                             基本数据项:用于描述一个 对象的某种属性的一个值,如姓名、日期或证件号等,是数据中可命名的最小逻辑数据单位,即原子数据。

                             组合数据项:由多个基本数据项组成。

                (2)、记录。记录是一组相关的数据项的集合,用于描述一个对象在某方面的属性,如一个考生报名记录包括姓名、出生日期、报考学校代号、身份证等

                             一系列域。

                (3)、文件。文件是指由创建者所定义的一组相关信息的集合,逻辑上可分为有结构文件无结构文件两种。在有结构文件中,文件由一组相似记录组成,

                            如报考某学校的所有考生的报考信息记录,又称为记录式文件;而无结构文件则被看成是一个字符流,比如一个二进制文件或字符文件,又称为流式文件


                  虽然上面给出了结构化的表述,但实际上关于文件并无严格的定义。通常在操作系统中将程序和数据组织成文件。文件可以是数字、字母或二进制代码,基本

              访问单元可以是字节、行或记录。文件可以长期存储于硬盘或其他二级存储器中,允许可控制的进程间共享访问,能够被组织成复杂的结构


    -------文件属性:

             文件有一定的属性,这根据系统的不同而有所不同,但是通常都包括如下属性。

             (1)、名称。文件名称唯一,以容易读取的形式保存。

             (2)、标识符。标识文件系统内文件的唯一标签,通常为数字,它是对人不可读的一种内部名称。

             (3)、类型。被支持不同类型的文件系统所使用。

             (4)、位置。指向设备和设备上文件的指针。

             (5)、大小。文件当前大小(用字节、字或块表示),也可包含文件允许的最大值。

             (6)、保护。对文件进行保护的访问控制信息。

             (7)、时间、日期和用户标识。文件创建、上次修改和上次访问的相关信息,用于保护、安全和跟踪文件的使用。

     

               所有文件的信息都保存在目录结构中,而目录结构也保存在外存上。文件信息当需要时再调入内存。通常,目录条件包括文件名臣及其唯一标识符,而

        标识符定位其他属性的信息。


    --------文件的基本操作:

              文件属于抽象数据类型。为了恰当地定义文件,就需要考虑有关文件的操作。操作系统提供系统调用,它对文件进行创建、写、读、定位和截断。

              (1)、创建文件。创建文件有两个必要步骤,一是在文件系统中为文件找到空间;二是在目录中为新文件创建条目,该条目记录文件名称、在文件

                        系统中的位置及其其他可能信息。

              (2)、写文件。为了写文件,执行一个系统调动,指明文件名称和要写入文件的内容。对于给定文件名称,系统搜索文件目录以查找文件位置。系统

                       必须为该文件维护一个写位置的指针。每当发生写操作,便更新写指针。

              (3)、读文件。为了读文件,执行一个系统调用,指明文件名称和要读入文件块的内存位置。同样,需要搜索目录以找到相关目录项,系统维护一个

                      读位置的指针。每当发生读操作时,更新读指针。一个进程通常只一个文件读或写,所以当前操作位置可作为每个进程当前文件位置指针。由于

                     读和写操作都使用同一指针,节省了空间也降低了系统复杂度。

             (4)、文件重定位(文件寻址)。按某条件搜索目录,将当前文件位置设为给定值,并且不会读、写文件。

             (5)、删除文件。先从目录中找到要删除文件的目录项,使之称为空项,然后回收该文件所占用的存储空间。

             (6)、截断文件。允许文件所有属性不变,并删除文件内容,即将其长度设为 0 并释放其空间。

               补充:这6个基本操作可以组合到执行其他文件操作。例如,一个文件的复制,可以创建行文件、从旧文件读出并写入新文件。


    --------文件的打开与关闭:

                因为许多文件操作都涉及为给定文件搜索相关目录条目,许多系统要求在首次使用文件时,使用系统调用 open ,将指明文件的属性(包括该文件在外存上

           的物理位置)从外存拷贝到内存打开文件目录表的一个表目中,并将该表目的编号(或称为索引)返回给用户。操作系统维护一个包含所有打开文件信息的表

          (打开文件表,open-file table) 。当用户需要一个文件操作时,可通过该表的一个索引指定文件,就省略了搜索环节。当文件不再使用时,进程可以关闭它,

            操作系统从打开文件表中删除这一条目。

                大部分操作系统要求在文件使用之前就被显式打开。操作 open 会根据文件名搜索目录,并将目录条目复制到打开文件表。如果调用 open 的请求(创建、

            只读、读写、添加等)得到允许,进程就可以打开文件,而 open 通常返回一个指向打开文件表中的一个条目的指针。通过使用该指针(而非文件名)进行

           所有的 I / O 操作,以简化步骤并节省资源。

                注意,open 调用完成之后,操作系统对该文件的任何操作,都不再需要文件名,只需要 open 调用返回的指针。 


              整个系统表包含进程相关信息,如文件在磁盘的位置访问日期和大小。一个进程打开一个文件,系统打开文件表就会为打开的文件增加相应的条目。当另一个

        进程执行 open 时,只不过是在其进程打开表中增加一个条目,并指向整个系统表的相应条目。通常,系统打开文件表的每个文件时,还用一个文件打开计数器(Open

           Count ),以记录多少进程打开了该文件。每个关闭操作 close 则使得  Count  递减,当打开计数器为 0 时,表示该文件不再使用。系统将回收分配给该文件的内存空

        间等资源,若文件被修改过,则将文件写回外存,并将系统打开文件表中相应条目删除,最后释放文件的文件控制块(FCB)。


              每个打开文件都有如下关联信息:

             》》文件指针:系统跟踪上次读写位置作为当前文件位置指针,这种指针对打开文件的某个进程来说是唯一的,因此必须与磁盘文件属性分开保存。

             》》文件打开计数器:文件关闭时,操作系统必须重用其打开文件表条目,否则表内空间不够用。因为多个进程可能打开同一个文件,所以系统在删除打开文件条目

                    之前,必须等待最后一个进程关闭文件。该计数器跟踪打开和关闭的数量,当该计数为  0 时,系统关闭文件,删除该条目。

             》》文件磁盘位置:绝大多数文件操作都要求系统修改文件数据。该信息保存在内存中,以免为每个操作都从磁盘中读取。

             》》访问权限:每个进程打开文件都需要有一个访问模式(创建、只读、读写、添加等),该信息保存在进程的打开文件表中,以便操作系统能允许或拒绝之后的

                    I / O 请求。


              

          

          

                

       

           

        

               


                        

    展开全文
  • C语言文件操作详解

    万次阅读 多人点赞 2016-03-04 15:50:58
    C语言文件操作函数 函数介绍 文件打开与关闭操作 fopen():文件打开操作 头文件:stdio.h 函数定义:FILE *fopen(char *pname, char *mode) 函数说明:pname是文件名,mode是打开文件的方式 mode:"r" 打开一...

    C语言文件操作函数

    函数介绍

    文件打开与关闭操作

    fopen():文件打开操作

    头文件:stdio.h
    函数定义:FILE *fopen(char *pname, char *mode)
    函数说明:pname是文件名,mode是打开文件的方式
    mode:"r" 打开一个已经存在的文件文本,文件不存在则出错



    以“r+”的方式打开一个文件,会清空文件的原始内容,重新写入数据

    返回值:正常返回:FILE *一个指向文件在内存中的文件信息去的开头

    异常返回:NULL,表示打开操作不成功

    打开文件的作用是:
    (1)分配给打开文件一个FILE 类型的文件结构体变量,并将有关信息填入文件结构体变量;
    (2)开辟一个缓冲区;
    (3)调用操作系统提供的打开文件或建立新文件功能,打开或建立指定文件;
    FILE *:指出fopen是一个返回文件类型的指针函数;

     返回值
       正常返回:被打开文件的文件指针。
       异常返回:NULL,表示打开操作不成功。

     要说明的是:C语言将计算机的输入输出设备都看作是文件。例如,键盘文件、屏幕文件等。ANSI C标准规定,在执行程序时系统先自动打开键盘、屏幕、错误三个文件。这三个文件的文件指针分别是:标准输入stdin、标准输出stdout和标准出错 stderr。

     fclose():文件关闭

    函数定义int fclose(FILE *fp);

    函数说明:fp是一个以打开的文件的文件指针

    返回值:

    正常返回:0

    异常返回:EOF,表示文件在关闭时发生错误


    fgetc:读取一个字符

    函数定义:int fgetc(FILE *fp)

    函数说明:从fp中读取一个字符,作为返回值返回

    返回值:

    正常返回:返回读取字符的代码

    异常返回:返回EOF。例如:要从“写打开”的文件中读取一个字符时,会发生错误而返回一个EOF

    【例8.1】显示指定文件的内容。

    //程序名为:display.c
    //执行时可用:display filename1 形式的命令行运行。显示文件filename1中的内容。例如,执行命令行display display.c将在屏幕上显示display的原代码。
    
    //File display program.
    #include <stdio.h>
    void main(int argc,char *argv[]) //命令行参数
    {
        int ch;//定义文件类型指针
        FILE *fp;//判断命令行是否正确
        if(argc!=2)
        {
            printf("Error format,Usage: display filename1\n");
            return; //键入了错误的命令行,结束程序的执行
        }
        //按读方式打开由argv[1]指出的文件
        if((fp=fopen(argv[1],"r"))==NULL)
        {
            printf("The file <%s> can not be opened.\n",argv[1]);//打开操作不成功
            return;//结束程序的执行
        }
        //成功打开了argv[1]所指文件
        ch=fgetc(fp); //从fp所指文件的当前指针位置读取一个字符
        while(ch!=EOF) //判断刚读取的字符是否是文件结束符
        {
            putchar(ch); //若不是结束符,将它输出到屏幕上显示
            ch=fgetc(fp); //继续从fp所指文件中读取下一个字符
        } //完成将fp所指文件的内容输出到屏幕上显示
        fclose(fp); //关闭fp所指文件
    }



    fputc:写一个字符到文件中

    函数定义:int fputc(int ch, FILE*fp)

    函数说明:ch是一个整型变量,要写到文件的字符

    fp:文件指针,要写入的文件

    返回值:

    正常返回:要写入的字符的代码

    异常返回:返回EOF

    【例8.2】将一个文件的内容复制到另一个文件中去。

    //程序名为:copyfile.c
    //执行时可用:copyfile filename1 filename2形式的命令行运行,将文件filename1中的内容复制到文件filename2中去。
    //file copy program.
    #include <stdio.h>
    void main(int argc,char *argv[]) //命令行参数
    {
        int ch;
        FILE *in,*out; //定义in和out两个文件类型指针
        if(argc!=3) //判断命令行是否正确
        {
            printf("Error in format,Usage: copyfile filename1 filename2\n");
            return; //命令行错,结束程序的执行
        }
        //按读方式打开由argv[1]指出的文件
        if((in=fopen(argv[1],"r"))==NULL)
        {
            printf("The file <%s> can not be opened.\n",argv[1]);
            return; //打开失败,结束程序的执行
        }
        //成功打开了argv[1]所指文件,再
        //按写方式打开由argv[2]指出的文件
        if((out=fopen(argv[2],"w"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[2]);
            return; //打开失败,结束程序的执行
        }
        //成功打开了argv[2]所指文件
        ch=fgetc(in); //从in所指文件的当前指针位置读取一个字符
        while(ch!=EOF) //判断刚读取的字符是否是文件结束符
        {
            fputc(ch,out); //若不是结束符,将它写入out所指文件
            ch=fgetc(in); //继续从in所指文件中读取下一个字符
        } //完成将in所指文件的内容写入(复制)到out所指文件中
        fclose(in); //关闭in所指文件
        fclose(out); //关闭out所指文件
    }


    【例8.3】按十进制和字符显示文件代码,若遇不可示字符就用井号"#"字符代替之。

    //程序名为:dumpf.c
    //执行时可用:dumpf filename1 形式的命令行运行。
    // File dump program.
    #include <stdio.h>
    void main(int argc,char *argv[])
    {
        char str[9];
        int ch,count,i;
        FILE *fp;
        if(argc!=2)
        {
            printf("Error format,Usage: dumpf filename\n");
            return;
        }
        if((fp=fopen(argv[1],"r"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[1]);
            return;
        }
        count=0;
        do{
            i=0;
            //按八进制输出第一列,作为一行八个字节的首地址
            printf("%06o: ",count*8);
            do{
                // 从打开的文件中读取一个字符
                ch=fgetc(fp);
                // 按十进制方式输出这个字符的ASCII码
                printf("%4d",ch);
                // 如果是不可示字符就用"#"字符代替
                if(ch<' '||ch>'~') str[i]='#';
                // 如果是可示字符,就将它存入数组str以便形成字符串
                else str[i]=ch;
                // 保证每一行输出八个字符
                if(++i==8) break;
            }while(ch!=EOF); // 遇到文件尾标志,结束读文件操作
            str[i]='\0'; // 在数组str加字符串结束标志
            for(;i<8;i++) printf(" "); // 一行不足八个字符用空格填充
            printf(" %s\n",str); // 输出字符串
            count++; // 准备输出下一行
        }while(ch!=EOF); // 直到文件结束
        fclose(fp); // 关闭fp所指文件
    }
    


    fgets():从文件中读取一个字符串

    函数定义:char *fgets(char *str, int n, FILE *fp)

    函数说明:由fp指出的文件中读取n-1个字符,并把他们存放到有str指出的字符数组中区,最后加上一个由字符串结束符'\0'

    参数说明:str:接受字符串的内存地址,可以是数组别名,也可以是指针

    n:指出要读取的字符的个数

    fp:这个是文件指针,指出要从中读取字符的文件

    返回值:

    正常返回:字符串的内存首地址,即str的值

    异常返回:返回一个NULL值,此时应当用feof()或ferror()函数来判别是读取到了文件尾,还是发生了错误。

    fputs():写入字符串到文件中去

    函数定义:把由str之处的字符串写入到fp所指的文件中去

    函数说明:

    str:之处要写入到文件中去的字符串,不包括最后的'\0'

    fp:这个是文件指针,之处字符串要写入到的文件指针

    返回值:

    正常返回:写入到的文件的字符个数,即字符串的长度

    非正常返回:返回一个NULL值,此时应当用feof()或ferror()函数来判别是读取到了文件尾,还是发生了错误。

    5.实例

    【例8.4】以下程序将一个文件的内容附加到另一个文件中去。

    //程序名:linkfile.c
    //执行时可用:linkfile filename1 filename2形式的命令行运行,将文件filename2的内容附加在文件filename1之后。
    // file linked program.
    #include <stdio.h>
    #define SIZE 512
    void main(int argc,char *argv[])
    {
        char buffer[SIZE];
        FILE *fp1,*fp2;
        if(argc!=3)
        {
            printf("Usage: linkfile filename1 filename2\n");
            return;
        }
        // 按追加方式打开argv[1] 所指文件
        if((fp1=fopen(argv[1],"a"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[1]);
            return;
        }
        if((fp2=fopen(argv[2],"r"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[2]);
            return;
        }
        // 读入一行立即写出,直到文件结束
        while(fgets(buffer,SIZE,fp1)!=NULL)
            printf("%s\n",buffer);
        while(fgets(buffer,SIZE,fp2)!=NULL)
            fputs(buffer,fp1);
        fclose(fp1);
        fclose(fp2);
        if((fp1=fopen(argv[1],"r"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[1]);
            return;
        }
        while(fgets(buffer,SIZE,fp1)!=NULL)
            printf("%s\n",buffer);
        fclose(fp1);
    }


    E. 往文件中写格式化数据

    1.函数原型

    int fprintf(FILE *fp,char *format,arg_list)

    2.功能说明
      将变量表列(arg_list)中的数据,按照format指出的格式,写入由fp指定的文件。fprintf()函数与printf()函数的功能相同,只是printf()函数是将数据写入屏幕文件(stdout)。
    3.参数说明
      fp:这是个文件指针,指出要将数据写入的文件。
      format:这是个指向字符串的字符指针,字符串中含有要写出数据的格式,所以该字符串成为格式串。格式串描述的规则与printf()函数中的格式串相同。
    arg_list:是要写入文件的变量表列,各变量之间用逗号分隔。
    4.返回值
      无。
    5. 实例

    【8.5】下列程序的执行文件为display.exe,执行时键入命令行:
       display [-i][-s] filename
    下面的表格列出了命令行参数的含义及其功能:

    //存储文件名:save.txt
    //程序代码如下:
    // file display program.
    #include <stdio.h>
    void main()
    {
        char name[10];
        int nAge,nClass;
        long number;
        FILE *fp;
        if((fp=fopen("student.txt","w"))==NULL)
        {
            printf("The file %s can not be opened.\n","student.txt");
            return;
        }
        fscanf(stdin,"%s %d %d %ld",name,&nClass,&nAge,&number);
        fprintf(fp,"%s %5d %4d %8ld",name,nClass,nAge,number);
        fclose(fp);
        if((fp=fopen("student.txt","r"))==NULL)
        {
            printf("The file %s can not be opened.\n","student.txt");
            return;
        }
        fscanf(fp,"%s %d %d %ld",name,&nClass,&nAge,&number);
        printf("name nClass nAge number\n");
        fprintf(stdout,"%-10s%-8d%-6d%-8ld\n",name,nClass,nAge,number);
        fclose(fp);
    }


    G. 以二进制形式读取文件中的数据

    1. 函数原型

    int fread(void *buffer,unsigned sife,unsigned count,FILE *fp)

    2. 功能说明
      从由fp指定的文件中,按二进制形式将sife*count个数据读到由buffer指出的数据区中。
    3. 参数说明
    buffer:这是一个void型指针,指出要将读入数据存放在其中的存储区首地址。
    sife:指出一个数据块的字节数,即一个数据块的大小尺寸。
    count:指出一次读入多少个数据块(sife)。
    fp:这是个文件指针,指出要从其中读出数据的文件。
    4.返回值
      正常返回:实际读取数据块的个数,即count。
      异常返回:如果文件中剩下的数据块个数少于参数中count指出的个数,或者发生了错误,返回0值。此时可以用feof()和ferror()来判定到底出现了什么
    情况。

    H. 以二进制形式写数据到文件中去

    1. 函数原型

    int fwrite(void *buffer,unsigned sife,unsigned count,FILE *fp)

    2. 功能说明
      按二进制形式,将由buffer指定的数据缓冲区内的sife*count个数据写入由fp指定的文件中去。
    3. 参数说明
    buffer:这是一个void型指针,指出要将其中数据输出到文件的缓冲区首地址。
    sife:指出一个数据块的字节数,即一个数据块的大小尺寸。
    count:一次输出多少个数据块(sife)。
    fp:这是个文件指针,指出要从其中读出数据的文件。
    4.返回值
      正常返回:实际输出数据块的个数,即count。
      异常返回:返回0值,表示输出结束或发生了错误。
    5.实例

    【例8.7】

    #include <stdio.h>
    #define SIZE 4
    struct worker
    { int number;
        char name[20];
        int age;
    };
    void main()
    {
        struct worker wk;
        int n;
        FILE *in,*out;
        if((in=fopen("file1.txt","rb"))==NULL)
        {
            printf("The file %s can not be opened.\n","file1.txt");
            return;
        }
        if((out=fopen("file2.txt","wb"))==NULL)
        {
            printf("The file %s can not be opened.\n","file2.txt");
            return;
        }
        while(fread(&wk,sizeof(struct worker),1,in)==1)
            fwrite(&wk,sizeof(struct worker),1,out);
        fclose(in);
        fclose(out);
    }


    I. 以二进制形式读取一个整数

    1. 函数原型

    int getw(FILE *fp)

    2. 功能说明
      从由fp指定的文件中,以二进制形式读取一个整数。
    3. 参数说明
      fp:是文件指针。
    4. 返回值
      正常返回:所读取整数的值。
      异常返回:返回EOF,即-1。由于读取的整数值有可能是-1,所以必须用feof()或ferror()来判断是到了文件结束,还是出现了一个出错。
    5. 实例

    【例8.8】

    #include <stdio.h>
    void main(int argc,char *argv[])
    {
        int i,sum=0;
        FILE *fp;
        if(argc!=2)
        {
            printf("Command error,Usage: readfile filename\n");
            exit(1);
        }
        if(!(fp=fopen(argv[1],"rb")))
        {
            printf("The file %s can not be opened.\n",argv[1]);
            exit(1);
        }
        for(i=1;i<=10;i++) sum+=getw(fp);
        printf("The sum is %d\n",sum);
        fclose(fp);
    }


    J. 以二进制形式存贮一个整数

    1.函数原型

    int putw(int n,FILE *fp)

    2. 功能说明
     以二进制形式把由变量n指出的整数值存放到由fp指定的文件中。
    3. 参数说明
     n:要存入文件的整数。
     fp:是文件指针。
    4. 返回值
     正常返回:所输出的整数值。
     异常返回:返回EOF,即-1。由于输出的整数值有可能是-1,所以必须用feof()或ferror()来判断是到了文件结束,还是出现了一个出错。
    5. 实例

    【例8.9】

    #include <stdio.h>
    void main(int argc,char *argv[])
    {
        int i;
        FILE *fp;
        if(argc!=2)
        {
            printf("Command error,Usage: writefile filename\n");
            return;
        }
    
        if(!(fp=fopen(argv[1],"wb")))
        {
            printf("The file %s can not be opened.\n",argv[1]);
            return;
        }
        for(i=1;i<=10;i++) printf("%d\n", putw(i,fp));
        fclose(fp);
    }


    * 文件状态检查

    A. 文件结束
    (1) 函数原型

    int feof(FILE *fp)

    (2) 功能说明
       该函数用来判断文件是否结束。
    (3) 参数说明
       fp:文件指针。
    (4) 返回值
       0:假值,表示文件未结束。
       1:真值,表示文件结束。
    (5) 实例

    【例8.10】

    #include <stdio.h>
    void main(int argc,char *argv[])
    {
        FILE *in,*out;
        char ch;
        if(argc!=3)
        {
            printf("Usage: copyfile filename1 filename2\n");
            return;
        }
        if((in=fopen(argv[1],"rb"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[1]);
            return;
        }
        if((out=fopen(argv[2],"wb"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[2]);
            return;
        }
        while(!feof(in))
        {
            ch=fgetc(in);
            if(ferror(in))
            {
                printf("read error!\n");
                clearerr(in);
            }
            else
            {
                fputc(ch,out);
                if(ferror(out))
                {
                    printf("write error!\n");
                    clearerr(out);
                }
            }
        }
        fclose(in);
        fclose(out);
    }


    B. 文件读/写出错
    (1) 函数原型

    int ferror(FILE *fp)

    (2) 功能说明
       检查由fp指定的文件在读写时是否出错。
    (3) 参数说明
       fp:文件指针。
    (4) 返回值
       0:假值,表示无错误。
       1:真值,表示出错。

    C. 清除文件错误标志

    (1) 函数原型

    void clearerr(FILE *fp)

    (2) 功能说明
       清除由fp指定文件的错误标志。
    (3) 参数说明
       fp:文件指针。
    (4) 返回值
       无。
    (5) 实例

    【例8.12】

    #include <stdio.h>
    void main(int argc,char *argv[])
    {
        FILE *in,*out;
        char ch;
        if(argc!=3)
        {
            printf("Usage: copyfile filename1 filename2\n");
            return;
        }
        if((in=fopen(argv[1],"rb"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[1]);
            return;
        }
        if((out=fopen(argv[2],"wb"))==NULL)
        {
            printf("The file %s can not be opened.\n",argv[2]);
            return;
        }
        while(!feof(in))
        {
            ch=fgetc(in);
            if(ferror(in))
            {
                printf("read error!\n");
                clearerr(in);
            }
            else
            {
                fputc(ch,out);
                if(ferror(out))
                {
                    printf("write error!\n");
                    clearerr(out);
                }
            }
        }
        fclose(in);
        fclose(out);
    }


    D. 了解文件指针的当前位置
    (1) 函数原型

    long ftell(FILE *fp)

    (2) 功能说明
       取得由fp指定文件的当前读/写位置,该位置值用相对于文件开头的位移量来表示。
    (3) 参数说明
       fp:文件指针。
    (4) 返回值
       正常返回:位移量(这是个长整数)。
       异常返回:-1,表示出错。
    (5) 实例

    * 文件定位

    A. 反绕
    (1) 函数原型

    void rewind(FILE *fp)

    (2) 功能说明
       使由文件指针fp指定的文件的位置指针重新指向文件的开头位置。
    (3) 参数说明
       fp:文件指针。
    (4) 返回值
       无。
    (5) 实例

    【例8.14】

    #include <stdio.h>
    void main()
    {
        FILE *in,*out;
        in=fopen("filename1","r");
        out=fopen("filename2","w");
        while(!feof(in)) fputc(fgetc(in),out);
        rewind(out);
        while(!feof(in)) putchar(fgetc(in));
        fclose(in);
        fclose(out);
    }

    B. 随机定位
    (1) 函数原型

    int fseek(FILE *fp,long offset,int base)

    (2) 功能说明
       使文件指针fp移到基于base的相对位置offset处。
    (3)参数说明
       fp:文件指针。
       offset:相对base的字节位移量。这是个长整数,用以支持大于64KB的文件。
       base:文件位置指针移动的基准位置,是计算文件位置指针位移的基点。ANSI C定义了base的可能取值,以及这些取值的符号常量。

    (4)返回值

      正常返回:当前指针位置。
      异常返回:-1,表示定位操作出错。

    (5)实例
    【例8.15】

    #include <stdio.h>
    #include <string.h>
    struct std_type
    {
        int num;
        char name[20];
        int age;
        char class;
    }stud;
    int cstufile()
    {
        int i;
        FILE *fp;
        if((fp=fopen("stufile","wb"))==NULL)
        {
            printf("The file can't be opened for write.\n");
            return 0;
        }
        for(i=1;i<=100;i++)
        {
            stud.num=i;
            strcpy(stud.name,"aaaa");
            stud.age=17;
            stud.class='8';
            fwrite(&stud,sizeof(struct std_type),1,fp);
        }
        fclose(fp);
        return 1;
    }
    void main()
    {
        int n;
        FILE *fp;
        if(cstufile()==0) return;
        if((fp=fopen("stufile","rb"))==NULL)
        {
            printf("The file can not be opened.\n");
            return;
        }
        for(n=0;n<100;n+=2)
        {
            fseek(fp,n*sizeof(struct std_type),SEEK_SET);
            fread(&stud,sizeof(struct std_type),1,fp);
            printf("%10d%20s%10d%4c\n",stud.num,stud.name,stud.age,stud.class);
        }
        fclose(fp);
    }


    * 关于exit()函数
    1. 函数原型

    void exit(int status)

    2. 功能说明
      exit()函数使程序立即终止执行,同时将缓冲区中剩余的数据输出并关闭所有已经打开的文件。
    3. 参数说明
      status:为0值表示程序正常终止,为非0值表示一个定义错误。
    4. 返回值
      无。

    * 关于feof()函数
    1. 函数原型

    int feof(FILE *fp)

    2. 功能说明
       在文本文件(ASCII文件)中可以用值为-1的符号常量EOF来作为文件的结束符。但是在二进制文件中-1往往可能是一个有意义的数据,因此不能用它 来作为文件的结束标志。为了能有效判别文件是否结束,ANSI C提供了标准函数feof(),用来识别文件是否结束。
    3. 参数说明
      fp:文件指针。
    4. 返回值
      返回为非0值:已到文件尾。
      返回为0值:表示还未到文件尾。

    展开全文
  • 【C语言】文件(FILE)

    千次阅读 多人点赞 2019-04-05 23:19:07
    文章目录一、文件1.1 文件类型指针1.2 文件的打开与关闭1.2.1 文件的打开1.2.2 文件的关闭1.3 文件的读写1.3.1 文本文件的读写1.3.1.1 写字符函数fputc和读字符函数fgetc1.3.1. 2 写字符串函数fputs和读字符串函数...

    一、文件

            在程序运行时,常常需要将一些数据(运行的最终结果和中间数据)输出到磁盘上存放起来,以后需要时再从磁盘中输入到计算机内存。这就要用到磁盘文件。
    C语言把文件看作是一个字符(字节)的序列,即一个一个字符(字节)的数据顺序组成。根据数据的组织形式,可分为ASCII文件和二进制文件。ASCII文件又称文本文件,它的每一个字节放一个ASCII代码,代表一个字符。二进制文件是把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放。
            在过去使用的C版本(如UNIX系统下使用的C)有两种对文件的处理方法:一种叫“缓冲文件系统”,一种叫“非缓冲文件系统”。所谓缓冲文件系统是指系统自动地在内存中为每一个正在使用的文件名开辟一个缓冲区。从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘去。如果从磁盘向内存读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(给程序变量)。缓冲区的大小由各个具体的C版本确定,一般为512字节。

    在这里插入图片描述
    所谓“非缓冲文件系统”是指系统不自动开辟确定大小的缓冲区,而由程序为每个文件设定缓冲区。
    UNIX系统下,用缓冲文件系统来处理文本文件,用非缓冲文件系统处理二进制文件。用缓冲文件系统进行的输入输出又称为高级(或高层)磁盘输入输出(高层I/O),用非缓冲文件系统进行的输入输出又称为低级(低层)输入输出系统。ANSI C标准决定不采用非缓冲文件系统,而只采用缓冲文件系统。即既用缓冲文件系统处理文本文件,也用它来处理二进制文件。也就是将缓冲文件系统扩充为可以处理二进制文件。
    在C语言中,没有输入输出语句,对文件的读写都是用库函数来实现的。ANSI规定了标准输入输出函数,用它们对文件进行读写。

    1.1 文件类型指针

            缓冲文件系统中,关键的概念是“文件指针”。每个被使用的文件都在内存中开辟一个区,用来存放文件的有关信息(如文件的名字、文件状态及文件当前位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统定义的,取名为FILE。

    1.2 文件的打开与关闭

    1.2.1 文件的打开

    在这里插入图片描述

    #include <malloc.h>
    #include <stdio.h>
    // 主函数
    int main(int argc, char *argv[]) // *argv[]:指针数组
    {
      FILE *fp; // 文件指针
      fp = fopen("input.txt","r"); // 打开文件
      read/write fucntions // 读或者写函数
      fclose(fp); // 关闭文件指针
    
      return 0;
    }
    

    说明

    (1)用“r”方式打开的文件只能用于向计算机输入而不能用作向该文件输出数据,而且该文件应该已经存在,不能用“r”方式打开一个并不存在的文件(即输入文件),否则出错。
    (2)用“w”方式打开的文件只能用于向该文件写数据(即输出文件),而不能用来向计算机输入。如果原来不存在该文件,则在打开时新建立一个以指定的名字命名的文件。如果原来已存在一个以该文件名命名的文件,则在打开时将该文件删去,然后重新建立一个新文件。
    (3)如果希望向文件末尾添加新的数据(不希望删除原有数据),则应该用“a”方式打开。但此时该文件必须已存在,否则将得到出错信息。打开时,位置指针移到文件末尾。
    (4)用“r+”、“w+”、 “a+”方式打开的文件既可以用来输入数据,也可以用来输出数据。用“r+”方式时该文件应该已经存在,以便能向计算机输入数据。用“w+”方式则新建立一个文件,先向此文件写数据,然后可以读此文件中的数据。用“a+”方式打开的文件,原来的文件不被删去,位置指针移到文件末尾,可以添加,也可以读。
    (5)如果不能实现“打开”的任务,fopen函数将会带回一个出错信息。出错的原因可能是用“r”方式打开一个并不存在的文件;磁盘出故障;磁盘已满无法建立新文件等。此时fopen函数将带回一个空指针值NULL。	
    (6)在向计算机输入文本文件时,将回车换行符转换为一个换行符,在输出时把换行符转换成为回车和换行两个字符。在用二进制文件时,不进行这种转换,在内存中的数据形式与输出到外部文件中的数据形式完全一致,一一对应。
    (7)在程序开始运行时,系统自动打开3个标准文件:标准输入、标准输出、标准出错输出。这3个文件都与终端相联系。因此以前所用到的从终端输入或输出都不需要打开终端文件。系统自动定义了3个文件指针stdin、stdout和stderr,分别指向终端输入、终端输出和标准出错输出(也从终端输出)。如果程序中指定要从stdin所指的文件输入数据,就是指从终端键盘输入数据。
    

    1.2.2 文件的关闭

    在使用完一个文件后应该关闭它,以防止它再被误用。“关闭”就是使文件指针变量不指向该文件,也就是文件指针变量与文件“脱钩”,以后不能再通过该指针对原来与其相联系的文件进行读写操作。除非再次打开,使该指针变量重新指向该文件。

    1.3 文件的读写

    1.3.1 文本文件的读写

    1.3.1.1 写字符函数fputc和读字符函数fgetc

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

    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[]) // *argv[]:指针数组
    {
    
      FILE *fp;
      fp = fopen("input.txt", "r");
      if (fp == NULL)
      {
        exit(1);
      }
    
      char c;
      c = fgetc(fp);
      
      while (c != EOF)
      {
        putchar(c);
        c = fgetc(fp);
      }
    
      return 0;
    }
    
    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[]) // *argv[]:指针数组
    {
    
      FILE *fp;
      char filename[10]; //文件名
      printf("input file name: ");
      scanf("%s", &filename);
      
    
      if ((fp = fopen(filename, "w")) == NULL)
      {
        exit(1);
      }
    
      
      fflush(stdin); // 将缓冲区内的数据写回参数stream指定的文件中
      printf("input character\n");
      char c;
      c = getchar(); // 输入字符
      while (c != '#') // 判别
      {
        fputc(c, fp);
        c = getchar();
      }
    
      return 0;
    }
    

    在这里插入图片描述

    2、 将一个磁盘文件中的信息复制到另一个磁盘文件中

    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[]) // *argv[]:指针数组
    {
    
      FILE *in, *out;
      char infile[10]; //文件名
      char outfile[10];
    
      printf("enter the infile name:\n");
      scanf("%s", infile);
    
      printf("enter the outfile name:\n");
      scanf("%s", outfile);
    
      if ((in = fopen("input.txt", "rb")) == NULL)
        exit(0);
    
      if ((out = fopen("out.txt", "wb")) == NULL)
        exit(0);
    
      char c;
      c = fgetc(in);
      while (!feof(in)) // 判断文件是否结果
      {                // 判断文件不为空
        fputc(c, out); // 写入到out.txt文件中
        c = fgetc(in); // 循环读取下一个字符
      }
      
    
      fclose(in);
      fclose(out);
    
      return 0;
    }
    
    

    1.3.1. 2 写字符串函数fputs和读字符串函数fgets

    1、将学生数据,由键盘输入并存储到磁盘文件中

    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[]) // *argv[]:指针数组
    {
    
      FILE *fp;
      char student[50]; // 创建字符数组-存储输入的字符串
    
      printf("input filename:");
      scanf("%s", student);
    
      if ((fp = fopen("input.txt", "w")) == NULL)
      {
        exit(1);
      }
    
      for (int i = 0; i < 3; i++)
      {
        gets(student); // 获取输入的字符串
        fputs(student, fp);// 存储到文件fp
        fputs("\n", fp);
    
      }
    
      fclose(fp);
      return 0;
    }
    

    2、从上例文件中读取学生数据,并显示在屏幕上

    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[]) // *argv[]:指针数组
    {
    
      FILE *fp;
      if ((fp = fopen("input.txt", "r")) == NULL)
        exit(0);
    
      char string[80];
      while (fgets(string, 80, fp) != NULL)
      {
        printf("%s", string);
      }
    
      fclose(fp);
      return 0;
    }
    

    1.3.1.3 格式化写函数fprintf和格式化读函数fscanf

    1、将学生数据,由键盘输入并存储到磁盘文件中

    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[]) // *argv[]:指针数组
    {
    
      FILE *fp;
      if ((fp = fopen("input.txt", "w")) == NULL)
        exit(0);
    
      long num;
      char name[10];
      int age;
    
      for (int i = 0; i < 5; i++) {
    
        printf("第%d个学生:\n", i + 1);
        printf("学号:\n");
        scanf("%ld", &num);
    
        printf("姓名:\n");
        scanf("%s", &name);
    
        printf("年龄:\n");
        scanf("%d", &age);
    
        fprintf(fp, "学号:%ld 姓名:%9s 年龄:%d\n", num, name, age);
      }
    
      fclose(fp);
    
      return 0;
    }
    

    2、从上例文件中读取学生数据,并显示在屏幕上

    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[]) {
      FILE *fp;
    
      if ((fp = fopen("student.txt", "r")) == NULL)
        exit(0);
    
      long num;
      char name[10];
      int age;
    
      while (!feof(fp)) {
    
        // fprintf(fp, "学号:%ld 姓名:%9s 年龄:%d\n", num, name, age);
        fscanf(fp, "学号:%ld 姓名:%9s 年龄:%d\n", &num, name, &age);
        printf("%ld %s %d\n", num, name, age);
      }
    
      fclose(fp);
    
      return 0;
    }
    
    

    1.3.2 二进制文件的读写

    1.3.1 fread函数和fwrite函数

    从键盘输入4个学生数据,然后把它们转存到磁盘文件上去,然后再从磁盘文件中一次性读入内存并显示出来

    #include <stdio.h>
    #include <stdlib.h>
    
    struct student
    {
      long num;
      char name[10];
      int age;
    } s[4];
    
    // 主函数
    int main(int argc, char *argv[])
    {
      FILE *fp;
    
      if ((fp = fopen("student.dat", "w")) == NULL)
        exit(0);
    
      for (int i = 0; i < 4; i++)
      {
        printf("第%d个学生:\n", i + 1);
        printf("学号:\n");
        scanf("%ld", &s[i].num);
        printf("姓名:\n");
        scanf("%s", s[i].name);
        printf("年龄:\n");
        scanf("%d", &s[i].age);
      }
    
      fwrite(s, sizeof(struct student), 4, fp);
    
      rewind(fp);
      // for (int i = 0; i < 4; i++)
      // {
      //   fread(&s, sizeof(struct student), 1, fp);
      //   printf("%ld %s %d\n", s->num, s->name, s->age);
      // }
    
      fread(s, sizeof(struct student), 4, fp);
      for (int i = 0; i < 4; i++)
      {
        printf("%ld %s %d\n", s[i].num, s[i].name, s[i].age);
      }
    
      fclose(fp);
      return 0;
    }
    
    

    1.3.3 文件的定位

    文件中有一个位置指针,指向当前读写的位置。如果顺序读写一个文件,每次读写一个字符,则读写完一个字符后,该位置指针自动移动指向下一个字符位置。如果想改变这样的规律,强制使位置指针指向其他指定的位置,可以用有关函数。

    1.3.3.1 rewind()函数

    rewind函数的作用是使位置指针重新返回文件的开头,此函数没有返回值。
    有一个磁盘文件,第一次将它的内容显示在屏幕上,第二次把它复制到另一文件上

    /*
     * @Author: jjk
     * @Date: 2019-03-31 10:02:20
     * @Last Modified by: jjk
     * @Last Modified time: 2019-04-02 13:15:13
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    struct student
    {
      long num;
      char name[10];
      int age;
    } s[4];
    
    // 主函数
    int main(int argc, char *argv[])
    {
      FILE *fp;
    
      if ((fp = fopen("input.txt", "r")) == NULL)
        exit(0);
    
      char c;
      c = fgetc(fp);
      while (!feof(fp))
      {
    
        printf("%c", c);
        c = fgetc(fp);
      }
    
      FILE *fp2;
      if ((fp2 = fopen("student2.txt", "w")) == NULL)
        exit(0);
    
      rewind(fp); // 重置文件指针
    
      c = fgetc(fp);
      while (!feof(fp))
      {
        fputc(c, fp2);
        c = fgetc(fp);
      }
    
      fclose(fp);
      fclose(fp2);
    
      fclose(fp);
      return 0;
    }
    
    

    1.3.3.2 fseek()函数和随机读写

    对流式文件可以进行顺序读写,也可以进行随机读写,关键在于控制文件的位置指针。如果位置指针是按字节位置顺序移动的,就是顺序读写;如果能将位置指针按需要移动到任意位置,就可以实现随机读写。所谓随机读写,是指读写完上一个字符(字节)后,并不一定要读写其后的字符(字节),而可以读写文件中任意位置上所需要的字符(字节)。

    	用fseek函数可以实现改变文件的位置指针。
    	在磁盘文件上存有10个学生的数据。要求将第1、3、5、7、9个学生数据输入计算机,并在屏幕上显示出来
    
    /*
     * @Author: jjk
     * @Date: 2019-03-31 10:02:20
     * @Last Modified by: jjk
     * @Last Modified time: 2019-04-02 13:15:13
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    struct student
    {
      long num;
      char name[10];
      int age;
    } s[10];
    
    // 主函数
    int main(int argc, char *argv[])
    {
    
      FILE *fp;
    
      if ((fp = fopen("student.dat", "w+")) == NULL)
        exit(0);
    
      for (int i = 0; i < 10; i++)
      {
        printf("第%d个学生:\n", i + 1);
        printf("学号:\n");
        scanf("%ld", &s[i].num);
        printf("姓名:\n");
        scanf("%s", s[i].name);
        printf("年龄:\n");
        scanf("%d", &s[i].age);
      }
    
      fwrite(s, sizeof(struct student), 10, fp);
    
      struct student stu;
    
      for (int i = 1; i <= 9; i = i + 2)
      {
        fseek(fp, (i - 1) * sizeof(struct student), SEEK_SET);
        fread(&stu, sizeof(struct student), 1, fp);
        printf("%ld %s %d\n", stu.num, stu.name, stu.age);
      }
    
      fclose(fp);
    
      return 0;
    }
    
    

    在这里插入图片描述

    1.3.3.3 ftell()函数

    ftell函数的作用是得到流失文件中的当前位置,用相对于文件开头的位移量来表示。由于文件中的位置指针经常移动,往往不容易知道其当前位置。用ftell函数可以得到当前位置。

    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[])
    {
    
      FILE *stream;
    
      long position;
      char list[100];
      if ((stream = fopen("7-4-1.avi", "rb")) != NULL) // 二进制文件
      {
        // Move the pointer by reading data:
        fread(list, sizeof(char), 100, stream);
        // Get position after read:
        position = ftell(stream); // 获取当前指针位置
        printf("Position after trying to read 100 bytes: %ld\n", position);
        fclose(stream);
      
      }
    
      fclose(stream);
    
      return 0;
    }
    
    
    

    1.4 文件的检测

    1.4.1 ferror()函数

    1.4.2 clearerr函数

    #include <stdio.h>
    #include <stdlib.h>
    
    // 主函数
    int main(int argc, char *argv[]) {
    
      int count, total = 0;
      char buffer[100];
      FILE *stream;
    
      long position;
      char list[100];
    
      if ((stream = fopen("input.txt", "r")) == NULL)
        exit(1);
    
      int c;
      putc('c', stdin); //标准写入
      if (ferror(stdin)) {
        perror("Write error");
        //clearerr(stdin); // 清除这个错误:标准的输入文件处于正常状态
      }
    
      
      /* See if read causes an error. */
      printf("Will input cause an error? ");
      c = getc(stdin);
      if (ferror(stdin)) {
        perror("Read error");
        clearerr(stdin);
      }
    
      fclose(stream);
    
      return 0;
    }
    

    在这里插入图片描述

    1.5 总结

    在这里插入图片描述

    展开全文
  • c++文件操作大全

    万次阅读 多人点赞 2020-10-28 08:28:51
    c++文件操作大全 基于C的文件操作  在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。 一、流式文件操作 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义...
  • 文件系统

    千次阅读 2018-09-05 09:17:21
    操作系统层:即文件系统,操作系统如何将各个硬件管理并对上提供更高层次接口; 单机引擎层:常见存储系统对应单机引擎原理大概介绍,利用文件系统接口提供更高级别的存储系统接口; 分布式层:如何将多个...
  • 文件管理

    万次阅读 2018-10-11 16:07:13
    1.下列文件物理结构中,适合随机访问且易于文件扩展的是() 连续结构 索引结构 链式结构且磁盘块定长 链式结构且磁盘块变长 解析: 文件的物理结构包括连续、链式、索引三种,其中链式结构...
  • 文件文件

    千次阅读 2019-08-08 20:16:26
    文件文件流 1. File类 Java.io.File类可以获取文件以及文件夹的一些基本的属性 常用的方法 文件名称,路径,大小,判断是否存在,删除,创建 // 创建一个文件对象(可以是文件,可以是文件夹) File file = new ...
  • FileDownload文件的下载

    千次阅读 2019-10-18 17:54:14
    文件的下载: 1)步骤: ①.设置contentType响应头:设置响应的类型是什么?通知浏览器是个下载的文件 response.setContentType("application/x-msdownload"); ②.设置Content-Disposition响应头:通知浏览器不在有...
  • 读取文件夹下所有的文件的文件名 DirectoryInfo[] list = new DirectoryInfo(@"D:\document").GetDirectories(); for (int i = 0; i < list.Length - 1; i++) { Console.WriteLine(list[i]); }???? 对...
  • 为什么80%的码农都做不了架构师?>>> ...
  • Springboot整合Mybatis,启动程序访问接口后报错:: java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure ...
  • mdb文件和accdb文件区别: mdb:是老版本文件扩展名。 accdb:是新版本的文件扩展名。 所以你创建mdb、accdb文件时,需要选择保存的类型以及版本,类似于word文件,有些是doc文件,有些是docx文件。 可以将...
  • github上如何下载单个文件

    万次阅读 多人点赞 2018-08-07 11:42:06
    一般情况下,在github中,需要下载整个项目时,可以点击... 但是,当我们只需要某个项目当中的一个小文件时,该怎么做呢? 方法 : 找到所需下载的文件,选择RAW -》右键-》从连接另存未见为。即可下载  ...
  • linux zip命令

    万次阅读 2008-04-14 16:27:00
    From:...有时候,我们还需要把文件压缩成一个文件,因而它们仅使用少量磁盘空间并能更快地通过互联网下载。 理解归档文件(archive file)和压缩文件(c
  • Android Studio SVN配置忽略文件

    万次阅读 2016-05-31 16:29:04
    Android Studio SVN配置忽略文件 1.用Android Studio创建一个项目,会在根目录和Module目录下自动生成.gitignore文件,貌似是Git的配置文件,和SVN没有关系。 2.打开Setting-Version Control-Ignored Files,...
  • 根本原因是我的C盘系统盘设置太小了,因为虚拟机复制文件时,会在系统盘生成临时文件,每次都把C盘塞满了,所以就无法复制了
  • .gitignore无效,不能过滤某些文件

    万次阅读 2014-07-10 16:46:06
    .gitignore文件只对还没有加入版本管理的文件起作用
  • linux 发现交换文件 ".swp

    万次阅读 多人点赞 2017-06-23 10:24:57
    今天在linux里修改文件时,不小心非正常关闭了文件。再次打开的时候提示 E325: 注意发现交换文件 "filename.swp",具体报错如下: E325: 注意 发现交换文件 ".nginx.conf.swp"  所有者: root 日期: Fri Jun ...
  • 问题 解决方法1: 右键--属性--安全--编辑--选择Users,勾选完全控制--确定--确定 完成 或 解决方法2: 1.右键--属性--安全--编辑 2.点击--添加 3.点击--高级 4.立刻查找--选择Everyone......
1 2 3 4 5 ... 20
收藏数 10,356,954
精华内容 4,142,781
关键字:

文件