首页 > 其他分享 >【C语言】⽂件操作

【C语言】⽂件操作

时间:2024-10-18 18:21:02浏览次数:3  
标签:fp 输出 pFile int C语言 FILE 操作 指针

⽂件操作

1. 为什么使⽤⽂件?

如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤⽂件。

2. 什么是⽂件?

磁盘(硬盘)上的⽂件是⽂件。
但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类的)。

2.1 程序⽂件

程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows环境后缀为.exe)。

2.2 数据⽂件

⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件。
本章讨论的是数据⽂件。
在以前各章所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到显⽰器上。
其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处理的就是磁盘上⽂件。

2.3 ⽂件名

⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。
⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀
例如: c:\code\test.txt
为了⽅便起⻅,⽂件标识常被称为⽂件名。

3. ⼆进制⽂件和⽂本⽂件?

根据数据的组织形式,数据⽂件被称为⽂本⽂件或者⼆进制⽂件。
数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存的⽂件中,就是⼆进制⽂件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂本⽂件。
⼀个数据在⽂件中是怎么存储的呢?
字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽⼆进制形式输出,则在磁盘上只占4个字节。
在这里插入图片描述
测试代码:

#include <stdio.h>
int main()
{
 int a = 10000;
 FILE* pf = fopen("test.txt", "wb");
 fwrite(&a, 4, 1, pf);//⼆进制的形式写到⽂件中
 fclose(pf);
 pf = NULL;
 return 0;
}

在VS上打开⼆进制⽂件:
在这里插入图片描述
10000在⼆进制⽂件中
在这里插入图片描述

4. ⽂件的打开和关闭

4.1 流和标准流

4.1.1 流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。
C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。
⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。

4.1.2 标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?
那是因为C语⾔程序在启动的时候,默认打开了3个流:
• stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
• stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中。
• stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
stdin、stdout、stderr 三个流的类型是: FILE * ,通常称为⽂件指针
C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。

4.2 ⽂件指针

缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”。
每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名 FILE.
例如,VS2013 编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:

struct _iobuf {
	 char *_ptr;
	 int _cnt;
	 char *_base;
	 int _flag;
	 int _file;
	 int _charbuf;
	 int _bufsiz;
	 char *_tmpfname;
};
typedef struct _iobuf FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。
每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构的变量,并填充其中的信息,使⽤者不必关⼼细节。
⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。
下⾯我们可以创建⼀个FILE*的指针变量:
FILE* pf;//⽂件指针变量
定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够间接找到与它关联的⽂件
⽐如:
在这里插入图片描述

4.3 ⽂件的打开和关闭

⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件。
在编写程序的时候,在打开⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和⽂件的关系。
ANSI C 规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件。

//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件
int fclose ( FILE * stream );

mode表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:
在这里插入图片描述
实例代码:

/* fopen fclose exampl
#include <stdio.h>
int main ()
{
	 FILE * pFile;
	 //打开⽂件
	 pFile = fopen ("myfile.txt","w");
	 //⽂件操作
	 if (pFile!=NULL)
	 {
		 fputs ("fopen example",pFile);
		 //关闭⽂件
		 fclose (pFile);
	 }
	 return 0;
}

5. ⽂件的顺序读写

5.1 顺序读写函数介绍

在这里插入图片描述
上⾯说的适⽤于所有输⼊流⼀般指适⽤于标准输⼊流和其他输⼊流(如⽂件输⼊流);所有输出流⼀般指适⽤于标准输出流和其他输出流(如⽂件输出流)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
fwrite
在这里插入图片描述
fread在这里插入图片描述

5.2 对⽐⼀组函数:

scanf/fscanf/sscanf
printf/fprintf/sprintf
在这里插入图片描述

6. ⽂件的随机读写

6.1 fseek

根据⽂件指针的位置和偏移量来定位⽂件指针(⽂件内容的光标)。

int fseek ( FILE * stream, long int offset, int origin );

在这里插入图片描述
在这里插入图片描述
例⼦:

/* fseek example */
#include <stdio.h>
int main ()
{
	 FILE * pFile;
	 pFile = fopen ( "example.txt" , "wb" );
	 fputs ( "This is an apple." , pFile );
	 fseek ( pFile , 9 , SEEK_SET );
	 fputs ( " sam" , pFile );
	 fclose ( pFile );
	 return 0;
}

6.2 ftell

返回⽂件指针相对于起始位置的偏移量

long int ftell ( FILE * stream );

在这里插入图片描述
例⼦:

/* ftell example : getting size of a file */
#include <stdio.h>
int main ()
{
	 FILE * pFile;
	 long size;
	 pFile = fopen ("myfile.txt","rb");
	 if (pFile==NULL) 
	 perror ("Error opening file");
	 else
	 {
		 fseek (pFile, 0, SEEK_END); // non-portable
		 size=ftell (pFile);
		 fclose (pFile);
		 printf ("Size of myfile.txt: %ld bytes.\n",size);
	 }
	 return 0;
}

6.3 rewind

让⽂件指针的位置回到⽂件的起始位置

void rewind ( FILE * stream );

在这里插入图片描述

例⼦:

/* rewind example */
#include <stdio.h>
int main ()
{
	 int n;
	 FILE * pFile;
	 char buffer [27];
	 
	 pFile = fopen ("myfile.txt","w+");
	 for ( n='A' ; n<='Z' ; n++)
	 fputc ( n, pFile);
	 rewind (pFile);
	 
	 fread (buffer,1,26,pFile);
	 fclose (pFile);
	 
	 buffer[26]='\0';
	 printf(buffer);
	 return 0;
}

7. ⽂件读取结束的判定

7.1 被错误使⽤的 feof

牢记:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。
feof 的作⽤是:当已知⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。

  1. ⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
    例如:
    • fgetc 判断是否为 EOF .
    • fgets 判断返回值是否为 NULL .
  2. ⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数。
    例如:
    • fread判断返回值是否⼩于实际要读的个数。
    在这里插入图片描述
    在这里插入图片描述
    ⽂本⽂件的例⼦:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	 int c; // 注意:int,⾮char,要求处理EOF
	 FILE* fp = fopen("test.txt", "r");
	 if(!fp) 
	 {
	 	perror("File opening failed");
	 	return EXIT_FAILURE;
	 }
	 //fgetc 当读取失败的时候或者遇到⽂件结束的时候,都会返回EOF
	 while ((c = fgetc(fp)) != EOF) // 标准C I/O读取⽂件循环
	 { 
	 	putchar(c);
	 }
	 //判断是什么原因结束的
	 if (ferror(fp))
	 	puts("I/O error when reading");
	 else if (feof(fp))
	 	puts("End of file reached successfully");
	 fclose(fp);
}

⼆进制⽂件的例⼦:

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
	 double a[SIZE] = {1.,2.,3.,4.,5.};
	 FILE *fp = fopen("test.bin", "wb"); // 必须⽤⼆进制模式
	 fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
	 fclose(fp);
	 double b[SIZE];
	 fp = fopen("test.bin","rb");
	 size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
	 if(ret_code == SIZE) 
	 {
		 puts("Array read successfully, contents: ");
		 for(int n = 0; n < SIZE; ++n) 
		 printf("%f ", b[n]);
		 putchar('\n');
	 } 
	 else 
	 { // error handling
		 if (feof(fp))
		 printf("Error reading test.bin: unexpected end of file\n");
		 else if (ferror(fp)) 
		 {
			 perror("Error reading test.bin");
		 }
	 }
	 fclose(fp);
}

8. ⽂件缓冲区

ANSIC 标准采⽤“缓冲⽂件系统” 处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的⼤⼩根据C编译系统决定的。

标签:fp,输出,pFile,int,C语言,FILE,操作,指针
From: https://blog.csdn.net/2402_85428625/article/details/142703224

相关文章

  • Mappest操作
    1publicstaticclassMappTest2{3publicstaticvoidRun()4{5varconfig=newTypeAdapterConfig();6//只要配置需要处理的类,并支持多个属性操作7config.ForType<MiddleClass,MiddleClass2>()8.Map(des......
  • ArkWeb页面加载与浏览记录导航 - 基础操作
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。简介在ArkWeb框架中,页面加载和浏览记......
  • 通义灵码操作指南
    点击链接,立即下载通义灵码插件:https://tongyi.aliyun.com/lingma/安装和登陆指南兼容IDE和系统本文介绍通义灵码IDE插件兼容的IDE、操作系统等。JetBrainsIDEsIDE版本:IntelliJIDEA、PyCharm、GoLand、WebStorm、AndroidStudio等2020.3及以上操作系统:Windows7......
  • 解决一下、在学习江协科技stm32f103开发板操作寄存器无法点亮小灯,但是可以正常熄灭遇
    目录 本人问题:目前搜集网上有关信息有两种解决方案: 本人问题:问题:学习江协科技用操作寄存器的方式进行点亮小灯,代码正确,但是点亮小灯无法点亮,需要重新拔下来下载器再插入电脑USB口才可以点亮。但是熄灭小灯可以正常实现。本人代码:点亮:#include"stm32f10x.h"......
  • C语言-分支循环语句 (上)
    C语言是结构化的程序设计语言,这里的结构指的是顺序结构、选择结构、循环结构,C语⾔是能够实现这三种结构的,其实我们如果仔细分析,我们日常所见的事情都可以拆分为这三种结构或者这三种结构的组合。实现分支结构可以使用if、switch,实现循环结构使用for、while、dowhil......
  • C++连接Simnow Linux API实现简单量化交易操作文档
    C++连接SimnowLinuxAPI实现简单量化交易技术文档写在前面:本文为本人学习上期所SimnowLinuxAPI连接行情和交易接口时整理的学习笔记,欢迎沟通交流~一、背景SimNow是上海期货交易所全资子公司上期技术公司专为投资者打造的期货模拟仿真交易平台,通过CTP系统,量化交易投......
  • IO操作
    基本概念System.IO命名空间有各种不同的类,用于执行各种文件操作,如创建和删除文件、读取或写入文件,关闭文件等。以下是一些常用的类及其用途:File类提供静态方法来读写文件,如复制、删除、移动文件等。File.Exists():判断文件是否存在if(File.Exists("D:\\test.txt"))Con......
  • 3191. 使二进制数组全部等于 1 的最少操作次数 I
    给你一个二进制数组nums。你可以对数组执行以下操作任意次(也可以0次):选择数组中任意连续3个元素,并将它们全部反转。反转一个元素指的是将它的值从0变1,或者从1变0。请你返回将nums中所有元素变为1的最少操作次数。如果无法全部变成1,返回-1。示例......
  • 初识TS-类型多种操作
    类型推论在ts中,没有明确指出类型,ts的类型推论会帮助提供类型类型断言当ts类型太宽泛的时候,可以使用类型断言 as 指定更加具体的类型constalink:HTMLElement=document.getElementById('link')alink.link?//这种写法会报错,HTMLElement类型太宽泛了正确写法//常用写......
  • python文件操作
    1.文件的编码思考:计算机只能识别:0和1,那么我们丰富的文本文件是如何被计算机识别,并存储在硬盘中呢?答案:使用编码技术(密码本)将内容翻译成0和1存入。计算机只认识0和1,所以需要将内容翻译成0和1才能保存在计算机中,同时也需要编码,将计算机保存的0和1,反向翻译回可以识别的内容不......