ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

C语言——文件

2021-11-15 18:02:15  阅读:193  来源: 互联网

标签:fp 文件 函数 C语言 FILE 缓冲区 指针


        许多程序在实现过程中,依赖于把数据保存到变量中,而变量是通过内存单元存储数据的,数据的处理完全由程序控制。当一个程序运行完成或终止运行,所有变量的值不再保存。当输入输出数据量较大时,就会受到限制,带来不便。

        文件是解决上述问题的有效办法,它通过把数据存储在磁盘文件中,得以长久保存。当有大量数据输入时,可通过编辑工具事先建立输入数据的文件,程序运行时将不再从键盘输入,而从指定的文件上读入,从而实现数据一次输入多次使用。同样,当有大量数据输出时,可以将其输出到指定文件,不受屏幕大小限制,并且任何时候都可以查看结果文件。一个程序的运算结果还可以作为其他程序的输入,进一步加工。

         

(1)文件的概念

        文件系统功能是操作系统的重要功能和组成部分。文件是指驻留在外部介质中的一个有序数据集,可以是源文件,目标程序文件,可执行程序,也可以是待输入的原始数据,或是一组输出的结果。

        使用应用程序时,通常保存功能实现把数据从内存写入到文件,这就是所谓的存盘。打开功能实现把磁盘文件的内容读入到内存 。

(2)文本文件和二进制文件

        根据数据存储的形式,文件的数据流分为字符流和二进制流,前者称为文本文件或字符文件,后者称为二进制文件。

(3)缓冲文件系统

        缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用,当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”装满后再从内存“缓冲区”依此读入接收的变量。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。

(4)文件结构与文件类型指针

FILE文件类型说明:

typedef struct{
	short level;            //缓冲区使用量 
	unsigned flags;         //文件状态标志 
 	char fd;                //文件描述符 
	short bsize;            //缓冲区大小 
	unsigned char *buffer;  //文件缓冲区的首地址 
	unsigned char *curp;    //指向文件缓冲区的工作指针 
	unsigned char hold;     //其他信息 
	unsigned istemp
	short token;
} FILE;

       上述定义中,文件结构本身用关键字 struct 进行定义,用typedef关键字把 struct 结构类型重新命名为 FILE 。struct 内部定义的成员包含了文件缓冲区的信息。

       自定义类型( typedef )不是用来定义一些新的数据类型,而是将C语言中的已有类型包括已定义的自定义类型重新命名,用新的名称代替已有数据类型,常用于简化对复杂数据类型定义的描述。如FILE就描述了整个 struct 的定义部分。

       自定义类型的一般形式为:

typedef <已有类型名> <新类型名>;

一般要求重新定义的类型名用大写。

       文件缓冲区是内存中用于数据存储的数据块,在文件处理过程中,程序需要访问该缓冲区实现数据的存取。因此,如何定义其中的具体数据,是文件操作类程序需要解决的首要问题。然而,文件缓冲区由系统自动分配,并不像数组那样可以通过数组名加下标来定位。为此,C语言引进FILE文件结构,其成员指针指向文件的缓冲区,通过移动指针实现对文件的操作。除此之外,在文件操作中还需用到文件的名字,状态,位置等信息

       C语言中的文件操作都是通过调用标准函数来完成的。由于结构指针的参数传递效率更高,因此C语言文件操作统一以文件指针方式实现。定义文件类型指针的格式为:

       FILE   * fp ;

其中,FILE是文件类型定义符,fp 是文件类型的指针变量。

       文件指针是特殊指针,指向的是文件类型结构,它是多项信息的综合体。每一个文件都有自己的FILE结构和文件缓冲区,FILE结构中有一个curp成员,通过 fp->curp, 可以指示文件缓冲区中数据存取的位置。

       注意:文件指针不像以前普通指针那样能进行 fp ++或 *fp 等操作, fp++将意味着指向下一个FILE结构(如果存在)。

       文件操作具有顺序性的特点,前一个数据取出后,下一次将顺序取后一个数据,fp->curp 会发生改变,但改变是隐含在文件读写操作中的,而不需要在编程时写上 fp->curp ++ ,这样类似的操作将由操作系统在文件读写时自动完成

(5)文件控制块

       已知文件缓冲区与磁盘文件之间的处理是由操作系统自动完成的,那么操作系统具体又是如何处理的呢?答案是通过操作文件控制块FCB( File Control Block)实现的。文件控制块包括文件属性,文件名,驱动器号,扩展名,文件长度以及文件记录状态等信息

       操作系统为了控制管理文件,采用文件表来管理文件,它给每一个文件顺序编号,并对应一个不同的FCB。程序要访问文件时,用一个FILE指针指向文件缓冲区,此时操作系统会把文件缓冲区与FCB相关联。因此不管有多少文件,操作系统都能有效地控制管理。如果程序想要对某个文件进行操作,只要告诉缓冲文件系统“要访问哪个文件”,操作系统会根据文件表立即在磁盘中找到该文件,并把相应的FCB编号与文件缓冲区关联。

(6)文件处理步骤

       1.定义文件指针

       2.打开文件:文件指针指向磁盘文件缓冲区

       打开文件功能用于建立系统与要操作的某个文件之间的关联,指定这个文件名并请求系统分配相应的文件缓冲区内存单元。打开文件由标准函数 fopen()实现,其一般调用形式为:

        fopen("文件名","文件打开方式");

说明:1.该函数有返回值。如果执行成功,函数将返回包含文件缓冲区等信息的FILE结构地址,赋给文件指针 fp。否则,返回一个NULL的FILE指针。        2.括号内的两个参数都是字符串。"文件名"指出要对哪个具体文件进行操作,一般要指定文件的路径,如果不写出路径,则默认与应用程序的当前路径相同。文件路径若包含绝对完整路径,则定位子目录用的斜杆‘ \ ’需要用双斜杠' \ '.

                                                                文件打开方式

文本文件(ASCII)
         使用方式含义
" r "打开文本文件进行只读
" w "建立新文本文件进行只写
" a "打开文本文件进行追加
" r+"打卡文本文件进行读 / 写
" w+"建立新文本文件进行读 / 写
" a+"打开文本文件进行读 / 写 / 追加

                                                   二进制文件打开方式比文本文件多了个 ' b '

       下面两种方式都以只读的方式打开 abc.txt 文件:

 fp = fopen ( " abc.txt "," r ") ;

或 char *p = " abc.txt " ;

     fp = fopen( p ," r ");

        执行标准函数 fopen(),计算机将完成下述步骤工作 :

1. 在磁盘中找到指定文件 .

2. 在内存中分配保存一个FILE类型结构单元(16B).

3. 在内存中分配文件缓冲区单元(521B).

4. 返回FILE结构地址(回送给 fp ).

    

        文件打开的实质是把磁盘文件与文件缓冲区对应起来,这样后面的文件读写操作只需使用文件指针即可。如果 fopen()返回NULL,表明文件无法正常打开,其原因可能是文件不存在,路径不对,或者文件已经被别的程序打开,也可能是文件存储有问题。为了保证文件操作的可靠性,调用 fopen()函数时最好做一个判断,以确保文件正常打开后再进行读写

        其形式:

if (( fp = fopen (" abc.txt ", " r ")) == NULL ) {

       printf(" File open error !\n ") ;

       exit ( 0 ) ;

}

        其中 exit ( 0 ) 是系统标准函数,作用是关闭所有打开的文件,并终止程序的运行。参数 0 表示程序正常结束,非 0 参数通常表示不正常的程序结束。

        一旦文件经 fopen()正常打开,对该文件的操作方式就被确定,并且直至文件关闭都不变,即若一个文件按 r 的方式打开,则只能对该文件进行读操作,而不能进行写入操作。

        一般进行文件读写操作时,常用到如下规则:

if  读文件

        指定的文件必须存在,否则出错;

if  写文件(指定的文件可以存在或不存在)

        if  以 " w " 方式写

                 if  该文件已经存在

                     原文件将被删去然后重新建立;

                  else

                     按指定的名字新建一个文件 ;

        if  以 " a " 方式写

                   if  该文件已存在

                       写入的数据将被添加到指定文件原有数据的后面,不会删去原来的内容;

                   else

                      与 " w " 相同 ;

if  文件同时读和写

                      使用 " r++ " , " w++ " 或 " a++ " 打开文件 ;

       C语言允许同时打开多个文件,不同文件采用不同文件指针指示,但不允许同一文件在关闭前被再次打开。

       3.文件处理:文件读写操作

字符方式文件读写函数: fgetc() 和 fputc()  ;

       对于文本文件,存取的数据都是ASCII码字符文本,使用这两个函数读写文件时,逐个字符地进行文本读写

       fgetc()函数实现从 fp 所指示的磁盘文件读入一个字符到 ch

       函数调用格式:

ch = fgetc( fp );

       该函数与 getchar()函数功能类似,getchar()从键盘上读入一个字符。

       fputc()函数把一个字符 ch 写到 fp 所指示的磁盘文件上。

       函数调用格式:

fputc( ch ,fp );

       函数返回值若写文件成功为 ch ,若写文件失败则为 EOF 。

       该函数同 putchar()函数类似,putchar( ch )把ch显示在屏幕上。EOF值为-1.

       

字符串方式文件读写函数 :fgets()和 fputs()

       这两个函数以字符串的方式来对文本文件进行读写。读写文件时一次读取或写入的是字符串。

       fputs()函数用来向指定的文本文件写入一个字符串。

       函数调用格式:

fputs( s ,  fp ) ;

       其中, s 是要写入的字符串,可以是字符数组名,字符型指针变量或者字符串常量, fp 是文件指针。该函数把 s 写入文件时,字符串 s 的结束符 ' \0 ' 不写入文件。

       若函数执行成功,函数返回所写的最后一个字符 ;否则,函数返回 EOF。

       fgets()用来从文本文件中读取字符串。

       函数调用格式:

fgets( s ,n,fp ) ;

       s 与 fputs()一样,n是指定读入的字符个数, fp 是文件指针。函数被调用时,最多读取

n-1 个字符,并将读入的字符串存入指针 s 所指向内存地址开始的 n-1 个连续的内存单元中。当函数读取的字符达到指定的个数,或接收到换行符,或接收到文件结束标志 EOF 时,将在读取的字符后面自动添加一个 ' \0 ' 字符;若有换行符,则将换行符保留(换行符在 ' \0' 字符之前);若有EOF,则不保留EOF。该函数若执行成功,返回读取的字符串;如果失败,返回空指针,这时,s的内容不确定。

格式化方式文件读写函数 fscanf() 和 fprintf()

       fscanf() 用于从文件中按照给定的控制格式读取数据,而 fprintf()用于按照给定的控制格式向文件写入数据。

       函数调用格式:

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

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

       例如:

FILE *fp;
int n;
flaot x;
 fp = fopen("a.txt","r");
 fscanf(fp,"%d %f",&n,&x);
 //从文件a.txt分别读入整型数到变量n,浮点数到变量x 

        

按组进行读写
fwrite()
size_t fwrite( const void*buffer , size_t size , size_t count , FILE *fp)
// 将一个数据块写入fp指向的文件中
// buffer是指向所要输出参数的地址 
// size是每次所要写入的字节数
// count是写入次数
// fp目标文件指针
// 读写成功则返回写入字节数

 


fread()
size_t fread( const void*buffer , size_t size , size_t count , FILE *fp)
// 从fp指向的文件中读取一个数据块
// buffer是指向所要读出的地址 
// size是每次所要读出的字节数
// count是读出次数
// fp目标文件指针
// 读写成功则返回读出字节数

 


位置指针
rewind()
void rewind( FILE *fp )
// 将位置指针重新定位到文件开头
// 没有返回值

fseek()
int fseek( FILE *fp ,long offset ,int start)
// fseek()可以按照需要任意移动位置
// offset是以start参数为起始位置的偏移量
// start 取值如下:
// SEEK_SET SEEK_CUR SEEK_END 
// 相应整数值为:0,1,2
// 分别表示:文件开头位置,当前位置,文件结束位置
// 成功则返回0,否则返回非0

ftell()
long ftell( FILE *fp )
// 获取位置指针当前位置相对于文件首的偏移字节数
// 函数调用成功则返回当前文件的读写位置,否则返回-1

文件出错检测
ferror()
int ferror( FILE *fp )
// 检测对文件指针fp所指向的文件读写操作出现的错误
// 没有出错则返回0,否则返回非0
// 由于每次进行读写操作后,再调用ferror()函数都会产生一个新的值
// 因此在调用读写操作函数后要及时地调用ferror()函数对其经行检测,否则信息会丢失

clearerr()
void clearerr( FILE *fp )
// 复位错误标志,无返回值

perror()
void perror( const char *string)
// 将上一个函数发生错误的原因输出到标准设备
// 参数string所指字符串先被打印,再加上错误原因字符串

strerror()
char *strerror( int errnum)
// 将错误的数值信息转化为易于理解的字符串信息


原文链接:https://blog.csdn.net/qq_45279570/article/details/108050221

       4.关闭文件

       当文件操作完成后应关闭它,防止不正常的操作。如果把数据写入文件,首先是写到文件缓冲区,只要当写满512B,才会由系统真正写入磁盘扇区。如果写的数据不到512B,发生程序异常终止,那么这些缓冲区中的数据就会丢失。当文件操作结束时,即使未写满512B,通过文件关闭,能强制把缓冲区中的数据写入磁盘扇区,确保写文件的正常完成。

       关闭文件通过调用标准函数 fclose ()实现,其一般格式为:

fclose (文件指针) ;

       该函数将返回一个整数,若 0 表示正常关闭文件,反之异常。所以关闭文件也应使用条件判断:

       if ( fclose ( fp )) {

            printf (" Can not close the file !\n");

               exit ( 0 ) ;

       关闭文件除了强制把缓冲区的数据写入磁盘外,还将释放文件缓冲区单元和FILE结构,使文件指针与具体文件脱钩

       在编写程序时应养成文件使用结束后及时关闭文件的习惯,一则确保数据完整写入文件,二则及时释放不用的文件缓冲区单元

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

#include<stdio.h>
#include<stdlib.h>
int main()
{
    FILE*fp=NULL;
    char filename[25];
    char ch;
    printf("输入你要保存到的文件的名称:\n");
    gets(filename);
    if((fp=fopen(filename,"w"))==NULL)
    {
        printf("error: cannot open file!\n");
        exit(0);
    }
    printf("现在你可以输入你要保存的一些字符,以#结束:\n");
    getchar();
    while((ch=getchar())!='#'){
        fputc(ch,fp);
    }
    fclose(fp);
    system("pause");
    return 0;
}

以上实例运行输出结果为:

输入你要保存到的文件的名称:
test.txt
现在你可以输入你要保存的一些字符,以#结束:
www.runoob.com
#

    实例:    有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩),计算出平均成绩,况原有的数据和计算出的平均分数存放在磁盘文件"stud"中

#include<stdio.h>
#include<stdlib.h>
typedef struct{
    int ID;
    int math;
    int English;
    int C;
    int avargrade;
    char name[20];
}Stu;
int main()
{
    FILE*fp;
    Stu stu[5];
    int i,avargrade=0;
    printf("请输入5个同学的信息:学生号,姓名,3门成绩:\n");
    for(i=0;i<5;i++)
    {
        scanf("%d %s %d %d %d",&(stu[i].ID),stu[i].name,&(stu[i].math),&(stu[i].English),&(stu[i].C));
        stu[i].avargrade=(stu[i].math+stu[i].English+stu[i].C)/3;
    }
    
    if((fp=fopen("stud","w"))==NULL)
    {
        printf("error :cannot open file!\n");
        exit(0);
    }
    for(i=0;i<5;i++)
        fprintf(fp,"%d %s %d %d %d %d\n",stu[i].ID,stu[i].name,stu[i].math,stu[i].English,
                stu[i].C,stu[i].avargrade);
    
    fclose(fp);
    // system("pause");
    return 0;
}

以上实例运行输出结果后:

请输入5个同学的信息:学生号,姓名,3门成绩:
1 a 60 70 80
2 b 60 80 90
3 c 59 39 89
4 e 56 88 98
5 d 43 88 78

打开 stud文件,内容如下

1 a 60 70 80 70
2 b 60 80 90 76
3 c 59 39 89 62
4 e 56 88 98 80
5 d 43 88 78 69

题目:有两个磁盘文件A和B,各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件C中。

程序分析:你需要先创建 A.txt 与 B.txt。

A.txt文件内容:

123

B.txt文件内容:

456
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    FILE*fa,*fb,*fc;
    int i,j,k;
    char str[100],str1[100];
    char tem;
    if((fa=fopen("A.txt","r"))==NULL) // A.txt 文件需要存在
    {
        printf("error: cannot open A file!\n");
        exit(0);
    }
    fgets(str,99,fa);
    fclose(fa);
    if((fb=fopen("B.txt","r"))==NULL)  // B.txt 文件需要存在
    {
        printf("error: cannot open B file!\n");
        exit(0);
    }
    fgets(str1,100,fb);
    fclose(fb);
    strcat(str,str1);
    for(i=strlen(str)-1;i>1;i--)
        for(j=0;j<i;j++)
            if(str[j]>str[j+1])
            {
                tem=str[j];
                str[j]=str[j+1];
                str[j+1]=tem;
            }
    
    if((fc=fopen("C.txt","w"))==NULL)  // 合并为 C.txt
    {
        printf("error: cannot open C file!\n");
        exit(0);
    }
    fputs(str,fc);
    fclose(fc);
    system("pause");
    return 0;
}

以上实例运行输出结果后,打开 C.txt 内容如下:

123456

题目:从键盘输入一个字符串,将小写字母全部转换成大写字母,然后输出到一个磁盘文件"test"中保存。 输入的字符串以!结束。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
 
int main()
{
    FILE*fp=NULL;
    char str[50];
    int i,len;
    printf("输入一个字符串:\n");
    gets(str);
    len=strlen(str);
    for(i=0;i<len;i++)
    {
        if(str[i]<='z'&&str[i]>='a')
            str[i]-=32;
    }
    if((fp=fopen("test","w"))==NULL)
    {
        printf("error: cannot open file!\n");
        exit(0);
    }
    fprintf(fp,"%s",str);
    fclose(fp);
    
    system("pause");
    return 0;
}

标签:fp,文件,函数,C语言,FILE,缓冲区,指针
来源: https://blog.csdn.net/m0_61897853/article/details/121266765

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有