C语言_文件操作(上)

news2024/11/15 17:26:35

目录

1. 什么是文件

2. 文件名

3. 文件类型

4. 文件缓冲区

5. 文件指针

6. 文件的打开和关闭_fopen_fclose

7. 文件的顺序读写

7.1 fputc

7.2 fgetc

7.3 fputs

7.4 fgets

7.5 fscanf

7.6 fprintf

7.7 fread

7.8 fwrite

7.9 对比scanf/printf、fscanf/fprintf、sscanf/sprintf


        我们刚刚学习过了动态版的通讯录,试想一下,如果我们每次打开通讯录,都需要对所需要的好友进行重复增加,当退出通讯录以后,所加的好友又会消失,往往复复,这将是一件很麻烦的事;我们当然希望把通讯录的信息存储下来,下次打开时还可以使用上次存储的信息;本节文件操作将会帮我们解决这个问题;

        一起开始文件操作的学习吧!

1. 什么是文件

磁盘上的文件就是本节所称的文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件

程序文件:包括源程序文件(后缀为.c)。目标文件(后缀为.obj)、可执行程序(后缀为.exe);

数据文件:文件的内容不一定是程序,而是程序运行时读写的数据。比如程序运行需要从中读取数据的文件,或者输出内容的文件。

本篇主要讨论的是数据文件;

2. 文件名

一个文件需要有唯一的文件标识,以便于用户识别和引用;

文件名包含3部分:文件路径+文件名主干+文件后缀  ag. c:\code\test.txt    为了方便起见,文件标识常被称为文件名

(c:\code称为文件路径;test称为文件名主干;.txt称为文件后缀)

3. 文件类型

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。(文本文件是我们可以看得懂的)

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件

如果要求在外存上以ASCII码的形式存储,则需要在存储之前进行转换。以ASCII字符的形式存储的文件就是文本文件

数据在内存中的存储方式:字符一律以ASCII形式存储,数值型数据既可以用ASCII形式储存,也可以使用二进制形式存储。

ag. 例如在内存中存储10000的储存形式:00000000  00000000  00100111  00010000 

如果以ASCII码的形式存储得到的是文本文件,占用5个字节:00110001  00110000  00110000  00110000  00110000  (ASCII码的存储方式是按照ASCII码表来存储的,10000中1对应49,也就是00110001,0对应48,也就是00110000)

如果以二进制的形式存储得到的是二进制文件,占用4个字节00000000  00000000  00100111  00010000

4. 文件缓冲区

 所谓的缓冲文件系统是指系统自动地在内存中为程序中的每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会首先送到输出缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区,充满输入缓冲区以后,再从缓冲区逐个地将数据送到程序数据区。缓冲区的大小根据C编译系统决定。

5. 文件指针

在缓冲文件系统中,关键的概念是“文件类型指针”,简称文件指针;

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(文件的名字、文件状态、文件的当前位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名为FILE

在stdio.h文件中拿到FILE的定义,该FILE是一个结构体变量,该结构体如下所示:

#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;

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并且填充其中的信息;一般来说都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

比方说我们创建一个文件指针变量:FILE* pf

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区的信息就能够访问该文件。也就是说,通过文件指针变量就能够找到与他关联的文件

简单来说该文件指针就类似与结构体指针的功能,我拿到文件指针就能够访问该文件指针指向的文件,并且进行相应地操作;当我们访问一个文件时,该文件指针指向的文件信息区中对应的成员变量就会发生相应的改变;

6. 文件的打开和关闭_fopen_fclose

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件

在编写程序的时候,在打开文件的同时,都会返回一个FILE* 的指针变量指向该文件,也相当于建立了指针和文件的关系。

ANSIC规定使用fopen的函数来打开文件,fclose来关闭文件。

函数定义:FILE* fopen(const char* filename,const char* mode);第一个参数是文件名,第二个参数是打开方式(具体如下表);

                  int fclose(FILE * stream);

 例如:读取文件,文件的读取方式为只读:

int main()
{
	//打开文件2022_12_24.txt
	//如果写F:\\新建文件夹\\新建文件夹\\VS2013\\2022_12_24\\2022_12_24\\text ,他表示绝对路径,绝对路径需要注意转义;\\转义再转义
	//而如果写text,则表示相对路径,默认相对路径和该编程项目文件在同一目录下
	//如果出现打开文件失败或者找不到文件,则需要注意是相对路径还是绝对路径,文件和工程文件是否在一起
	FILE* pf = fopen("F:\\新建文件夹\\新建文件夹\\VS2013\\2022_12_24\\2022_12_24\\text", "r");//“r”只读
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fclose(pf);
	pf = NULL;
	return 0;
}
//F:\新建文件夹\新建文件夹\VS2013 这是文件原本的存储路径,之所以写成F:\\新建文件夹\\新建文件夹\\VS2013
//是因为单个\t会被识别为转义字符,所以\\t 表示转义之后在进行转义;

 注意

1. 打开文件fopen也会出错,文件打开失败时,返回值为NULL;如果打开成功,会返回该文件指向的指针;打开文件以后,也需要fclose关闭文件,将文件所指向的指针赋值为空指针;

2. 打开文件的过程是:该文件所指向的指针首先向保存该文件的文件信息区访问,文件缓冲区满以后会访问该文件。关闭的过程同样如此,首先会访问文件缓冲区;

7. 文件的顺序读写

文件的顺序读写涉及的函数有:

字符输入函数:fgetc,适用于所有输入流   //读文件  函数原型:int fgetc(FILE* stream); 头文件:stdio.h

字符输出函数:fputc,适用于所有输出流  //写文件  函数原型:int fputc(int c,FILE* stream);

文本行输入函数:fgets,适用于所有输入流   //读取一行  函数原型:char* fgets(char* string,int n,FILE* stream);第一个参数是读取的数组,第二个参数是所能读取的最大数量,第三个参数是文件指针;

文本行输出函数:fputs,适用于所有输出流  //写一行  函数原型:int fputs(const char* string,FILE* stream);

格式化输入函数:fscanf,适用于所有输入流  //格式化读取程序  函数原型:int fscanf(FILE* stream,const char *format[,argument]……);

格式化输出函数:fprintf,适用于所有输出流  //格式化写程序  函数原型:int fprintf(FILE* stream,const char* format[,argument]……);

以上所有都是以文本形式输入/输出;        

以下是以二进制形式输入/输出;

二进制输入:fread,适用于文件  //读二进制文件  函数原型:size_t fread(void* buffer,size_t size,size_t count,FILE* stream);

二进制输出:fwrite,适用于文件  //写二进制文件  函数原型:size_t fwrite(const void* buffer,size_t size,size_t count,FILE* stream);

:流是一个高度抽象的概念;数据要操作各种各样的硬件,所采用的读写方式是不同的,所以为了简化这一抽象的过程,引入流的概念;

我们只需要知道程序向流中去输入数据,数据需要转换给不同的硬件,在这个过程中起着重要作用的就是流;我们要知道我们通过程序操作各种硬件,都是在流中进行的;

C语言程序只要运行起来,就默认的打开了3个流:

stdin:标准输入流---键盘;// 输入默认是键盘输入的程序

stdout:标准输出流---屏幕;//因为错误和输出的程序是需要我们视觉的,所以在屏幕

stderr:标准错误流---屏幕;

7.1 fputc

字符输出函数:fputc,适用于所有输出流  //写文件  函数原型:int fputc(int c,FILE* stream);

这个时候如果继续用fputc写文件,而写的内容为空,对于该打开方式来说,表示已经执行了该程序,原本写的内容会被覆盖;又因为fputc写文件并未写任何内容,所以文件为空; 

通过fputc写一个字符通过流到屏幕上,也就是stdout;

7.2 fgetc

字符输入函数:fgetc,适用于所有输入流   //读文件  函数原型:int fgetc(FILE* stream); 头文件:stdio.h

从流里面读取一个字符,也可以从stdin标准输入流里面读取,函数的返回值是读取到的ASCII,若读取失败,返回-1;

hello是通过fputc写入的,则可以通过pgetc获得;

从标准输入流里读取字符:意思就是程序运行,stdin表示标准输入流,可以理解为从键盘输入的,所以手动敲hello,会通过fgetc读出;每次读一个字符;所以用%c打印,是能够读取空白字符的;

能够读取空白字符的意思是:

通过fgetc读取输入数据流,该程序我读取5个字符,当我输入abcd\n时,在读取a b c d 后后面会空白换行-----2行,第一行是5个字符中的第五个,因为我输入数据流没有第五个字符,所以默认打印换行;第二行是\n,%c会打印成换行符;

7.3 fputs

文本行输出函数:fputs,适用于所有输出流  //写一行  函数原型:int fputs(const char* string,FILE* stream);

写或者输出一个字符串到流,通过%s打印出来,适用于所有的输出流(stdout);

 \n会认为是转义字符,打印换行;

通过fputs写标准输出流打印到屏幕:

7.4 fgets

文本行输入函数:fgets,适用于所有输入流   //读取一行  函数原型:char* fgets(char* string,int n,FILE* stream);第一个参数是读取的数组,第二个参数是所能读取的最大数量,第三个参数是文件指针;

从流里面读取一个字符串,也可以从标准输入流stdin里面读;

打开文件的方式是读r;文件里面存放的是helloworld welcome,fgets的第二个参数表示读的最大字符数,此处设置时5,会读取hell\n,转义字符\n占用一个;当不足4个字符时,会换行。

第二次读取会从第一次读取的结束处继续读取;

从标准输入流stdin读取字符,可以读取到空白字符

同样的,num设置为5,读取hell\n,\n占用一个字符,o wo 表示可以读取到空白字符;rld不足4个字符,\n转义字符打印成换行;

7.5 fscanf

格式化输入函数:fscanf,适用于所有输入流//格式化读取程序  函数原型:int fscanf(FILE* stream,const char *format[,argument]……);

fscanf就是读取fprintf已经写入文件的程序,将其打印下来;

7.6 fprintf

格式化输出函数:fprintf,适用于所有输出流 //格式化写程序  函数原型:int fprintf(FILE* stream,const char* format[,argument]……);

因为我们之前基于文件的读写操作都是字符/字符串,那么具有一定格式的程序是否可以文件操作呢?答案是可以的。

使用fscanf和fprintf将输出数据流打印到屏幕:

7.7 fread

二进制输入:fread,适用于文件  //读二进制文件  函数原型:size_t fread(void* buffer,size_t size,size_t count,FILE* stream);

二进制写入文件的程序是乱码,但是可以通过fread将文件中的内容读出来;

7.8 fwrite

二进制输出:fwrite,使用于文件 //写二进制程序  函数原型:size_t fwrite(const void* buffer,size_t size,size_t count,FILE* stream);

7.9 对比scanf/printf、fscanf/fprintf、sscanf/sprintf

程序原型:int sscanf(const char *buffer,const char * format[,argument]……);

程序原型:int sprintf(char *buffer,const char*format[,argument]……);

sprintf具有可以把结构体转换成字符串的能力:

(定义一个结构体,初始化结构体成员变量;运用sprintf函数,打印数组buf内容,结果发现,%s打印出来的结果是整个结构体的内容;表明sprintf可以将结构体转换成字符串的形式)

struct S
{
	int n;
	float score;
	char arr[20];
};
int main()
{
	struct S s = { 100, 3.14f, "abcdef" };
	struct S tmp = { 0 };
	char buf[1024] = { 0 };
	//sprintf功能是把格式化的数据转换成字符串存储到buf
	sprintf(buf, "%d %f %s", s.n, s.score, s.arr);
	//sscanf的功能是从buf中读取格式化的数据到tmp中
	sscanf(buf, "%d %f %s", &(tmp.n), &(tmp.score), &(tmp.arr));
	printf("%d %f %s", tmp.n, tmp.score, tmp.arr);

	return 0;
}

1. scanf/printf:是针对标准输入流/标准输出流的格式化输入/输出语句;

2. fscanf/fprintf:是针对所有输入流/所有输出流的格式化输入/输出语句;

3. sscanf/sprintf:sscanf是从字符串中读取格式化的数据

                                sprintf是把格式化数据输出成字符串

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/151067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java实现dwg转pdf

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、无奈选择第二种二、jar引入1.jar地址2.使用jar,完成dwg转为pdf总结前言 由于公司需要最近研究一个cad文件需要在浏览器中展示,经过研究发现大致有两种方式:…

JVM-围观如何打破双亲委派机制

下面手把手用代码来实现打破JVM的双亲委派机制一、Tomcat打破双亲委派机制以Tomcat类加载为例,Tomcat作为web容器, 那么它要解决什么问题呢?Tomcat 如果使用默认的双亲委派类加载机制行不行?1.1 Tomcat作为web容器, 那…

科技云报道:CES 2023:自动驾驶、元宇宙备受瞩目

科技云报道原创。 在被疫情扰乱了两年之后,2023年CES终于回归正常了。 1月5日-8日,CES 2023在拉斯维加斯举行。作为当前全球规模最大、影响力最广泛的消费类电子技术年展,本届展会涵盖的重要主题包括可持续性、数字健康、Web3与元宇宙以及人…

教你如何快速使用店铺管理系统

一、客户管理1、客户资料客户资料报表展示所有新客的数据信息,在此报表可进行会员开卡及新增客户操作;提交会员开卡表单之后,由数据助手更新该客户的会员卡信息至客户信息表单;点击新增客户弹出客户信息表单,默认客户分…

python自学之《21天学通Python》(8)

第11章 文件与文件系统 编写程序来解决实际项目时,很多时候都离不开文件和文件系统的操作。程序本身就是保存在文件系统的文件中的。文件既可以保存程序代码,也可以用来保存各种输入与输出数据。文件和文件系统的处理是任何高级程序设计语言必不可少的一…

Node.js教程笔记(一)

学习目标 1、初识Nodejs 2、fs文件系统模块 3、path路径模块 4、http模块 一、初识Node.js 1.1 浏览器中的JavaScript的运行环境 1、浏览器中的JavaScript的组成部分 2、为什么JavaScript可以在浏览器中被执行? 3、为什么JavaScript可以操作Dom和Bom&#xff…

智公网:公务员的专业限制有哪些?

公务员报考的要求越来越高了,尤其是限制专业这一块,直接阻断了很多人想要跨专业的想法。但是没有办法专业这个条件是硬性的,所以在报考之前一定要看清报考要求。 公务员性质也是比较特殊的,像是一些比较热门专业,在公…

线程安全☞原子性

何为原子性? 原子性:一条线程在执行一系列程序指令操作时,该线程不可中断。一旦出现中断,那么就可能会导致程序执行前后的结果不一致。与数据库中的原子性(事务管理体现)是相同的 概括:一段程序只能由一条…

Go语言设计与实现 -- 浅谈垃圾回收机制

概述 GC就是垃圾回收机制。而我们知道,内存区域是分成几个块儿的,例如: 堆区:为对象分配内存空间,在栈区和bss区之间存放函数参数,返回值,局部变量全局区:常量区(const…

第一批“阳康”涌向三亚,最大的赢家或是携程

在2022年接近尾声时,给居民出行带来近三年困扰的疫情防控,终于迎来了好消息。随着国家“新十条”防控新政策的出台以及优化,过去出门不便、频繁查验核酸码的时代一去不返。尤其是各地逐步放宽出入境管控政策后,在线旅游行业也迎来…

PMP的价值有哪些?

我个人认为,考证只有两个出发点是正确的。一是为了提升自己或者满足自己的兴趣,另一个是和自己的职业规划相关。 比如,有同学想提升自己英语能力,可以考四六级,或者更厉害一点的考雅思、托福。比如,有的同…

电脑自动关机是什么原因?4个解决方法,赶紧码住收藏!

正在使用电脑,突然自动关机。如果没有及时保存好资料,我们辛辛苦苦写的资料就会付诸东流。电脑自动关机是什么原因?其实主要是以下这4个方面的原因。你可以根据下面不同的原因来对症下药,寻找解决电脑自动关机的最好方法&#xff…

直播弹幕系统(七)- 利用动态创建队列完成直播间独立聊天

直播弹幕系统(七)- 利用动态创建队列完成直播间独立聊天前言一. 动态创建队列1.1 测试 - 动态创建队列1.2 测试 - 聊天室独立前言 上一篇 SpringBoot STOMP RabbitMQ(使用MQ替代Spring代理) 中主要讲解了如何整合STOMP以及Rabb…

Vue条件语句中v-if、v-else、v-else-if的用法

文章目录1、v-if和v-else结合使用1.1 出现的错误2、v-if、v-else-if和v-else的联合使用2.1 出现的错误3、如果想要同时切换多个元素3.1 效果展示1、v-if和v-else结合使用 v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面&#xff0c;否则它将不会被识别。 <span…

智能指针(二) shared_ptr 注意点

智能指针(二) shared_ptr 注意点 1 不存在 int * 到 shared_ptr 的隐式类型转换 void proc(shared_ptr<int> ptr) {cout << "ptr.use_count()" << ptr.use_count() << endl;cout << "调用成功" << endl;return; }in…

独立产品灵感周刊 DecoHack #043 - 互联网从业者的灵感数据库

本周刊记录有趣好玩的独立产品设计开发相关内容&#xff0c;每周发布&#xff0c;往期内容同样精彩&#xff0c;感兴趣的伙伴可以点击订阅我的周刊。为保证每期都能收到&#xff0c;建议邮件订阅。欢迎通过 Twitter 私信推荐或投稿。很完美的断更了2期&#xff0c;有一期是因为…

RFID技术和NFC技术的原理及区别,你都了解吗?

物联网是信息技术发展的重要推动力&#xff0c;推动了农业、工业、制造业、服务业等多个行业的发展&#xff0c;物联网主要由三个关键技术组成&#xff0c;即连接、物体标识和数据传输&#xff0c;人们把RFID技术作为物体标识的代表&#xff0c;随着技术的进步起源于RFID技术的…

谷粒商城-基础篇-Day07-品牌分类关联与级联更新

将品牌分类和品牌名称的关系放在pms_category_brand_relation表中 获取该列表品牌所有的关联信息 /*** 列表*/GetMapping("/catelog/list")public R list(RequestParam("brandId") Long brandId){List<CategoryBrandRelationEntity> datacategoryBra…

Java日期时间类

Java日期时间类Datenew Date()**获取当前系统时间**通过**指定毫秒数得到时间**format**指定日期格式**SimpleDateFormat的模式字母&#xff1a;parse()可以把**格式化的String转成对应Date**Calendar&#xff08;日历&#xff09;创建日期类对象获取日历对象的某个日历字段第三…

【Linux】五、Linux 进程控制(总)|进程创建|进程终止|进程等待进程程序替换|模拟shell

目录 一、进程创建 1.1 再谈 fork 函数 1.2 fork 函数返回值问题 1.2 写时拷贝 1.3 fork 常规用法 1.4 fork调用失败的原因 二、进程终止 2.1 进程退出码 2.2 进程退出场景 2.3 进程如何退出 三、进程等待 3.1 进程等待必要性 3.2 进程等待的方法 3.2.1 通过 wai…