C语言文件操作(超详细版)

2024-02-26 1211阅读

温馨提示:这篇文章已超过390天没有更新,请注意相关的内容是否还可用!

目录

C语言文件操作(超详细版)什么是文件

✨文件分类

  程序文件

  数据文件

C语言文件操作(超详细版)文件的使用

✨文件指针

文件指针的使用

✨文件的打开和关闭

文件的使用方式

✨文件的顺序读写

1.写入一个字符

2.读取一个字符

3.连续每次读取一个字符

4.覆盖并写入一行数据

5.读取指定长度的数据

6.将结构体信息写入文件中

7.读取文件信息到结构体变量中

8.二进制写入文件

9.读取二进制文件信息

10.sscanf()函数、sprintf()函数

C语言文件操作(超详细版)文件的随机读写

✨fseek()函数

✨ftell函数()

✨ rewind()函数

C语言文件操作(超详细版)二进制文件和文本文件

C语言文件操作(超详细版)文件读取结束判定

✨feof()函数

文本文件的判断

二进制文件的判断


C语言文件操作(超详细版)


📌————本章重点————📌

🔗文件指针

🔗文件的顺序读写

🔗文件的随机读写

🔗文件读取结束判定

 ✨————————————✨


什么是文件

        与普通文件载体不同,文件是以硬盘为载体存储在计算机上的信息集合,文件可以是文本文档、图片、程序等等。文件通常具有点+三个字母的文件扩展名,用于指示文件类型(例如,图片文件常常以KPEG格式保存并且文件扩展名为.jpg)。

        将数据放入文件中,相比代码程序中堆栈上的数据,其优点在于可以随时做到需要时添加、舍弃时删除,数据可以持久化。

文件分类:

        文件一般讲两种:程序文件和数据文件;

  程序文件:

        包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

  数据文件:

        包括程序运行时所读写的数据。本篇所涉及的就是数据文件。


文件的使用

文件的操作一般分三步:1.打开文件;2.读/写;3.关闭文件;

C语言文件操作(超详细版)

文件指针

        想要对文件进行操作,“文件指针”就是一个关键桥梁(亦名:文件类型指针);                

        底层原理:每个被使用的文件,都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如:文件名、文件状态、文件位置等),这些信息被保存到一个结构体中,系统为其声明为FILE,每当打开一个文件的时候,系统就会根据情况自动创建一个FILE结构的变量,并且通过FILE*的指针来维护这个结构。

文件指针的使用:

    FILE* pf;

定义一个文件指针变量pf,它可以指向某个文件的文件信息区,通过其即可访问到该文件。

C语言文件操作(超详细版)

C语言文件操作(超详细版)


文件的打开和关闭

        在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指

针和文件的关系。

  • fopen() —— 打开文件;
    • FILE * fopen ( const char * filename, const char * mode );
  • fclose() —— 关闭文件;
    • int fclose ( FILE * stream );

    文件的使用方式:

    按常用序:

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

    文件的顺序读写

    函数名功能适用性
    fgetc()字符输入函数所有输入流
    fputc()字符输出函数所有输出流
    fgets()文本行输入函数所有输入流
    fputs()文本行输出函数所有输出流
    fscanf()格式化输入函数所有输入流
    fprintf()格式化输出函数所有输出流
    fread()二进制输入文件
    fwrite()二进制输出文件

    以上结合起来实例:

    #include
    #include
    #include
    int main()
    {
    	FILE* pf= fopen("test.txt", "w+");
    	if (pf == NULL)
    	{
    		printf("%s\n", strerror(errno));
    		return;
    	}
    	//输入一个字符
    	fputc('a', pf);
    	//用完关闭文件
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }

    如图示:在源文件所在目录下,原本没有test.txt文件,是w+创建了这个新的文件,并写入一个字符a 

    C语言文件操作(超详细版)

    1.写入一个字符:

    //写文件    
        fputc('a', pf);

    2.读取一个字符:

    	//读取一个字符
    	int ch = fgetc(pf);
    	if (ch != EOF)
    	{
    		printf("%c\n", ch);
    	}

    3.连续每次读取一个字符:

    	//文件中有abcdefg
    	int ch = fgetc(pf);
    	printf("%c\n", ch);	//a
    	ch = fgetc(pf);
    	printf("%c\n", ch);	//b
    	ch = fgetc(pf);
    	printf("%c\n", ch);	//c
    	ch = fgetc(pf);
    	printf("%c\n", ch);	//d
    

    4.覆盖并写入一行数据:

    	fputs("hello world", pf);

    注意:这里fputs函数虽然是整行写入,但会覆盖掉原始数据、

    C语言文件操作(超详细版)

    5.读取指定长度的数据:

        //定一一个数组
    	char arr[10] = { 0 };
    	fgets(arr, 5, pf);    //将所读取的数据放入arr中
    	printf("%s\n", arr);
    

    C语言文件操作(超详细版)

    6.将结构体信息写入文件中:

    这里的结构体信息就是格式化的,那么就需要fprintf()函数了

    #include
    typedef struct S
    {
    	char name[10];
    	int age;
    }Peo;
    int main()
    {
    	FILE* pf = fopen("test.txt", "w");
    	if (pf != NULL)
    	{
    		Peo p = { "zhangsan", 18 };
    		fprintf(pf, "%s %d\n", p.name, p.age);
    		fclose(pf);
    		pf = NULL;
    	}
    	return 0;
    }

    C语言文件操作(超详细版)

    7.读取文件信息到结构体变量中:

    #include
    typedef struct S
    {
    	char name[10];
    	int age;
    }Peo;
    int main()
    {
    	FILE* pf = fopen("test.txt", "r");
    	if (pf != NULL)
    	{
    		Peo p = { 0 };
    		fscanf(pf, "%s %d", p.name, &p.age);
    		printf("%s %d", p.name, p.age);
    		fclose(pf);
    		pf = NULL;
    	}
    	return 0;
    }

    C语言文件操作(超详细版)

    8.二进制写入文件:

    • size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
      #include
      #include
      #include
      typedef struct S
      {
      	char name[10];
      	int age;
      }Peo;
      int main()
      {
      	FILE* pf = fopen("test.txt", "wb+");
      	if (pf != NULL)
      	{
      		Peo p = { "lisi", 19};
      		fwrite(&p, sizeof(Peo), 1, pf);
      		fclose(pf);
      		pf = NULL;
      	}
      	return 0;
      }

      C语言文件操作(超详细版)

      9.读取二进制文件信息:

      • size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

        #include
        typedef struct S
        {
        	char name[10];
        	int age;
        }Peo;
        int main()
        {
        	FILE* pf = fopen("test.txt", "rb+");
        	if (pf != NULL)
        	{
        		Peo p = { 0 };
        		fread(&p, sizeof(Peo), 1, pf);
        		printf("%s %d\n", p.name, p.age);
        		fclose(pf);
        		pf = NULL;
        	}
        	return 0;
        }
        

        C语言文件操作(超详细版)

        10.sscanf()函数、sprintf()函数:

        这两个函数虽然和文件操作关系不大,但是容易与文件操作函数混淆;

        • sscanf()函数:
          • int sscanf( const char *buffer, const char *format [, argument ] ... );
          • 将一个字符串转化为格式化数据;
            #include
            typedef struct S
            {
            	char name[10];
            	int age;
            }Peo;
            int main()
            {
            	//定义一个字符串
            	char buffer[] = { "zhansan 19" };
            	//定义一个结构但不赋值
            	Peo p = { 0 };
            	sscanf(buffer, "%s %d", p.name, &p.age);
            	return 0;
            }

            C语言文件操作(超详细版)

            • sprintf()函数:
              • int sprintf( char *buffer, const char *format [, argument] ... );

              • 将一个格式化数据转化为字符串;

                #include
                typedef struct S
                {
                	char name[10];
                	int age;
                }Peo;
                int main()
                {	
                	//定义一个结构
                	Peo p = { "zhangsan",19};
                	//定义一个字符串
                	char buffer[50] = { 0 };
                	sprintf(buffer, "%s %d\n", p.name, p.age);
                	return 0;
                }

                C语言文件操作(超详细版)


                文件的随机读写

                所谓的随机读写,其实就是指定我们想要读写的位置。

                fseek()函数:

                • 该函数可以从定位位置的偏移量处开始读写;
                • int fseek( FILE *stream, long offset, int origin );

                                       文件流          偏移量    起始位置 

                • 返回值:
                  1. 如果成功,fseek返回0;
                  2. 否则,它返回一个非零值;
                  3. 在无法查找的设备上,返回值未定义;        

                   三种定位指针:

                  C语言文件操作(超详细版)

                   使用实例:

                  #include
                  #include
                  #include
                  int main()
                  {
                  	FILE* pf = fopen("test.txt", "r");
                  	if (pf == NULL)
                  	{
                  		printf("%s\n", strerror(errno));
                  		return;
                  	}
                  	//开始多次读取
                  	//定位指针:比如要读取从头开始向后偏移 2 个单位的一个字符
                  	fseek(pf, 2, SEEK_SET);
                  	int ch = fgetc(pf);
                  	printf("%c\n", ch);
                  	//第二次读取:要拿到当前文件指针所处位置向后偏移5个单位的字符
                  	fseek(pf, 5, SEEK_CUR);
                  	ch = fgetc(pf);
                  	printf("%c\n", ch);
                  	//第三次读取:要拿到文件流末尾向前偏移8个单位的一个字符
                  	fseek(pf, -8, SEEK_END);
                  	ch = fgetc(pf);
                  	printf("%c\n", ch);
                  	fclose(pf);
                  	pf = NULL;
                  	return 0;
                  }

                  C语言文件操作(超详细版)

                  特别说明:

                          在每使用完一次fseek函数后,文件指针会自动向后移动一位:

                  C语言文件操作(超详细版)

                  ftell函数():

                  • 该函数可以返回文件指针相对于起始位置的偏移量;
                  • long int ftell ( FILE * stream );

                    使用实例:

                            我们直接在上一段代码的基础上加上ftell()函数即可直观得到每次文件指针所处的位置:

                    C语言文件操作(超详细版)

                     rewind()函数:

                    • 让文件指针回到文件初始位置;
                    • void rewind ( FILE * stream );

                      使用实例: 

                      C语言文件操作(超详细版)


                      二进制文件和文本文件

                      我们知道数据在内存中是以二进制形式存储的,对于文件而言:如果不加转换直接输出到外存就是二进制文件;如果要在外存上以ASCII码形式存储,就需要提前转换最后以ASCII码值形式存储的文件就是文本文件。

                      对于字符,一律使用ASCII码形式存储,但对于数值型数据,即可以使用ASCII码存储也可以使用二进制形式存储。

                      举例:

                      数字10000的两种存储形式:

                      二进制文件:

                      C语言文件操作(超详细版)

                      文本文件:

                      首先将10000分成'1','0','0','0','0', 这五个字符,用每个字符对应的ASCII码值进行转换:

                      C语言文件操作(超详细版)

                       

                       由此可见:对于10000在数,如果以二进制形式存储占用4个字节,如果以ASCII码存储占用5个字节。试想:那对于数字1呢?

                      显而易见,二进制文件存储和文本文件存储对不同范围的数字可以做到节省空间。

                      对二进制文件深入理解:

                      #include
                      int main()
                      {
                      	FILE* pf = fopen("test.txt", "wb");
                      	int a = 10000;
                      	if (pf != NULL)
                      	{
                      		fwrite(&a, 4, 1, pf);
                      		fclose(pf);
                      		pf = NULL;
                      	}
                      	return 0;
                      }

                      对于上面这段代码,我们知道是将数值10000放入了test.txt文件中,但我们无法直接看到它在文件中的真实值,于是使用vs的二进制编辑器即可查看:

                      C语言文件操作(超详细版)


                      文件读取结束判定

                      feof()函数:

                      该函数被许多人错误用来判断文件是否读取结束,其实它的作用是判断文件读取结束的原因;

                      文件读取结束有两种情况:1.读取过程中出现异常; 2.读取到文件末尾;

                      要找出文件读取是哪个原因,就分为以下情况:

                      文本文件:

                      • 如果用 fgetc() 读取,要判断 feof() 的返回值是否为EOF;
                      • 如果用 fgets() 读取,要判断 feof() 的返回值是否为NULL(0);

                        二进制文件:

                                都是使用 fread() 读取,要判断其返回值与指定读取个数的大小,如果小于实际要读的个数,就说明发生读取异常,如果等于实际要读的个数,就说明是因读取成功而结束;

                        对于读取异常的判断,我们考虑判断 ferror() 函数的返回值:

                        1. 若ferrror()为真——异常读取而结束;
                        2. 若feof()为真——正常读取到尾而结束;

                        文本文件的判断:

                        #include
                        #include
                        #include
                        int main()
                        {
                        	FILE* pf = fopen("test.txt", "r");
                        	if (pf == NULL)
                        	{
                        		perror("fopen is failed !");
                        		return;
                        	}
                        	int c = 0;
                        	//由于要检查EOF——EOF本质是0——所以是int
                        	while (c = fgetc(pf) != EOF)
                        	{
                        		putchar(c);
                        	}
                        	//直到while不执行了—读取结束了—判断是什么原因结束的
                        	if (ferror(pf))
                        	{
                        		printf("读取中出现错误\n");
                        	}
                        	else if (feof(pf))
                        	{
                        		printf("读取到文件尾\n");
                        	}
                        	fclose(pf);
                        	pf = NULL;
                        	return 0;
                        }

                        二进制文件的判断:

                        #include
                        #include
                        #include
                        int main()
                        {
                        	FILE* pf = fopen("test.txt", "rb");
                        	int arr[5] = { 0 };
                        	if (pf == NULL)
                        	{
                        		return;
                        	}
                        	size_t num = fread(arr, sizeof(int), 5, pf);
                        	if (num == 5)
                        	{
                        		//说明全部读取成功
                        		printf("Array read successfully\n");
                        	}
                        	else
                        	{
                        		//说明读取不够指定长度—判断是什么原因
                        		if (ferror(pf))
                        		{
                        			printf("读取中出现错误\n");
                        		}
                        		else if (feof(pf))
                        		{
                        			printf("读取到文件尾\n");
                        		}
                        	}
                        	fclose(pf);
                        	pf = NULL;
                        	return 0;
                        }
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]