C语言学习笔记(九):文件的操作

news2024/11/26 3:51:45

C文件的知识

什么是文件

操作系统把各种设备都统一作为文件来处理。例如,终端键盘是输入文件显示屏和打印机是输出文件。

文件一般指存储在外部介质上数据的集合操作系统是以文件为单位对数据进行管理的

输入输出是数据传送的过程,数据如流水一样从一处流向另一处,因此常将输入输出形象地称为流(stream),即数据流

c语言把文件看作一个字符(或字节的序列),一个输入输出流就是一个字符流或字节(内容为二进制数据)流。

C的数据文件由一连串的字符(或字节)组成,对文件的存取是以字符(字节)为单位的。输入输出数据流的开始和结束仅受程序控制而不受物理符号(如回车换行符)控。这种文件称为流式文件


文件的分类

根据数据的组织形式,数据文件可分为ASCII文件和二进制文件。数据在内存中是以二进制形式存储的,可以认为它就是存储在内存的数据的映像,所以也称之为映像文件(image file)。如果要求在外存上以ASCII代码形式存储,则需要在存储前进行转换。ASCII文件又称文本文件(text file),每一个字节存放一个字符的ASCII代码。

字符一律以ASCII形式存储数值型数据既可以用ASCII形式存储,也可以用二进制形式存储


数据的存储方式

  • 文本方式:数据以字符方式(ASCII代码)存储到文件中。如整数12,送到文件时占2个字节,而不是4个字节。以文本方式保存的数据便于阅读。
  • 二进制方式:数据按在内存的存储状态原封不动地复制到文件。如整数12,送到文件时和在内存中一样占4个字节。

文件缓冲区

ANSI C标准采用缓冲文件系统处理数据文件,所谓缓冲文件系统是指系统自动地在内存区为程序中每一个正在使用的文件开辟一个文件缓冲区。这样做是为了节省存取时间,提高效率,缓冲区的大小由各个具体的C编译系统确定。

image-20211221211621372


文件类型指针

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

typedef struct
{	short level;				//缓冲区“满”或“空”的程度
	unsigned flags;			//文件状态标志
	char fd;					//文件描述符
	unsigned char hold; 		//如缓冲区无内容不读取字符
	short bsize;				//缓冲区的大小
	unsigned char*buffer;	//数据缓冲区的位置
	unsigned char*curp;		//文件位置标记指针当前的指向
	unsigned istemp;		//临时文件指示器
	short token;				//用于有效性检查
}FILE;
FILE *f  //定义一个执行FILE类型数据的指针变量

/*f指向某一个文件信息区(结构体变量),通过文件指针变量能够找到与它有关联的文件,通常把这种指向文件信息区的变量简称为指向文件的指针变量*/

打开与关闭文件

fopen(打开文件)

FILE* fp;				//定义一个指向文件的指针变量fp
if ((fp=fopen(″file1″,″r″))==NULL) //若文件不存在.fopen返回一个null值
{	printf(″cannot open this file\n″);
	exit(0);
}
文件使用方式含义若文件不存在
r(只读)输入数据,打开已存在的文本文件出错
w(只写)输出数据,打开一个文本文件建立
a(追加)向文本文件末尾添加数据出错
rb(只读)输入数据,打开一个二进制文件出错
wb(只写)输出数据,打开一个二进制文件建立
ab(追加)向二进制文件追加数据出错
r+(读写)打开一个文本文件出错
w+(读写)建立一个新的文件建立
a+(读写)打开一个文本文件出错
rb+(读写)打开一个二进制文件出错
wb+(读写)建立一个新的二进制文件建立
ab+(读写)打开一个二进制文件出错

fclose(关闭文件)

fclose(fp)

顺序读写文件操作

向文件读写一个字符

函数功能返回值
fgetc(fp)从fp指向的文件读入一个字符读成功,带回所读的字符,失败则返回文件结束标志EOF(即-1)
fputc(ch,fp)把字符ch写到文件指针变量fp所指向的文件中输出成功,返回值就是输出的字符;输出失败,则返回EOF(即-1)
/*向文件输入字符*/
include <stdio.h>
include <stdlib.h>
int main()
{	FILE *fp;                     				//定义文件指针fp
	char ch,filename[10];
	printf("请输入所用的文件名: ");   
	scanf("%s",filename);        			//输入文件名
	getchar();                  		 		//用来消化最后输入的回车符
	if((fp=fopen(filename,"w"))==NULL)	//打开输出文件并使fp指向此文件
	{	printf("cannot open file\n");  	//如果打开出错就输出“打不开”
		exit(0);                       			//终止程序
	}
	printf("请输入一个准备存储到磁盘的字符串(以#结束): ");
	ch=getchar();        					//接收从键盘输入的第一个字符
	while(ch!='#')        					//当输入′#′时结束循环
	{	fputc(ch,fp); 					//向磁盘文件输出一个字符
		putchar(ch);					//将输出的字符显示在屏幕上
		ch=getchar(); 					//再接收从键盘输入的一个字符
	}
	fclose(fp);						//关闭文件
	putchar(10); 						//向屏幕输出一个换行符 
	return 0;
}

向文件读写一个字符串

函数功能返回值
fgets(str,n,fp)从fp指向的文件读入一个长度为(n-1)的字符串,存放到字符数组str中读成功,返回地址str,失败则返回NULL
fputs(str,fp)把str所指向的字符串写到文件指针变量fp所指向的文件中输出成功,返回0;否则返回非0值

/*将文件的内容输出到屏幕上*/
include <stdio.h>
include <stdlib.h>
int main()
{
	FILE* fp;
	char str[3][10];  
	int i = 0;
	if ((fp = fopen("123.txt", "r")) == NULL)	//打开有内容的文件 
	{
		printf("can′t open file!\n");
		exit(0);
	}
	while (fgets(str[i], 10, fp) != NULL)   //从fp指向的文件读字符,然后存到str数组里
	{
		printf("%s", str[i]);
		i++;
	}
	fclose(fp);
	return 0;
}

以格式化的方式读写文本文件

函数功能返回值
fprintf(fp,"格式化字符串", 输出变量)将格式化的数据写入文件指针指向的文件,可以指定输出格式。返回写入字符的数目,如果失败则返回一个负数
fscanf(fp,"格式化字符串",输入变量)从fp所指向的文件读入若干数据,并根据指定的格式读入到指定的内存地址中读入数据的项数,读到末尾返回EOF
int i=1;float f = 2.1;
fprintf (fp,%d,%6.2f,i,f);	//将变量i与变量f输出到fp指向的文件
fscanf (fp,%d,%f″,&i,&f);
//磁盘文件上如果有字符“3,4.5”,则从中读取整数3送给整型变量i,读取实数4.5送给float型变量f

用二进制的方式向文件读写数据

函数功能返回值
fread(输入缓冲区, 块大小, 块数, fp)从文件指针fp指向的文件中读取数据,一共读取块大小 × 块数个字节的数据,并存放到输入缓冲区中。返回实际读取的块数,如果读到文件末尾或读取错误,则返回小于块数的值。
fwrite(输出缓冲区, 块大小, 块数, fp)将输出缓冲区中的数据写入文件指针fp指向的文件中,一共写入块大小 × 块数个字节的数据。返回实际写入的块数,如果写入失败,则返回小于块数的值。
/*fread(buffer, size, count, fp)*/ 
float f[10];   
fread(f,4,10,fp);	//从fp所指向的文件读入10个4个字节的数据,存储到数组f中
/*fwrite(buffer, size, count, fp)*/ 
fwrite(f,4,10,fp)   //将f数组里10个4字节数据写到fp文件里
include <stdio.h>
define SIZE 10  
struct Student_type
{	char name[10];
	int num;
	int age;
	char addr[15];
}stud[SIZE];	//定义全局结构体数组stud,包含10个学生数据

void save()	//定义函数save,向文件输出SIZE个学生的数据
{	FILE *fp;
	int i;
	if((fp=fopen("stu.dat","wb"))==NULL)	//打开输出文件stu.dat
	{	printf("cannot open file\n");
		return;
	}
	for(i=0;i<SIZE;i++)
		if(fwrite(&stud[i],sizeof(struct Student_type),1,fp)!=1)
			printf("file write error\n");
	fclose(fp);
}

int main()
{	int i;
	printf("Please enter data of students:\n");
	for(i=0;i<SIZE;i++) 
	//输入SIZE个学生的数据,存放在数组stud中
	scanf("%s%d%d%s",stud[i].name,&stud[i].num,
		&stud[i].age,stud[i].addr);
	save();
	return 0;
}

随机读写数据文件

什么是随机读写

对文件进行顺序读写比较容易理解,也容易操作,但有时效率不高。而随机访问不是按数据在文件中的物理位置次序进行读写,而是可以对任何位置上的数据进行访问,显然这种方法比顺序访问效率高得多


文件位置标记

定义

为了对读写进行控制,系统为每个文件设置了一个文件读写位置标记(简称文件位置标记文件标记),用来指示“接下来要读写的下一个字符的位置”。

一般情况下,在对字符文件进行顺序读写时,文件位置标记指向文件开头,这时如果对文件进行读/写的操作,就读/写完第1个字符后,文件位置标记顺序向后移一个位置,依此类推,直到文件末尾。

流式文件既可以进行顺序读写,也可以进行随机读写,关键在于控制文件的位置标记。如果文件位置标记是按字节位置顺序移动的,就是顺序读写。如果能将文件位置标记按需要移动到任意位置,就可以实现随机读写


涉及函数

函数功能返回值
rewind(fp)将文件指针fp重新定位到文件的开头
fseek(fp,offset,origin)将文件指针fp以origin为起始点(0表文件开始位置,1表当前位置,2表文件末尾位置), 然后移动offset个字节0表示成功,非0值表示失败
ftell(fp)返回文件指针fp当前所指向的位置,单位是字节返回当前位置,如果失败则返回-1L
rewind(fp); //使文件位置标记指向文件开头,参数为文件指针,没有返回值
/*fseek(文件类型指针, 位移量, 起始点);该函数一般用于二进制文件
	“位移量”:指以“起始点”为基点,向前移动的字节数(长整型)
	“起始点”:用0,1或2代替,0代表“文件开始位置”,1为“当前位置”,2为“文件末尾位置”
*/
fseek (fp,100L,0);		//将文件位置标记向从文件开头处向前移动100个字节
fseek (fp,50L,1); 		//将文件位置标记向前移到离当前位置50个字节处
fseek (fp,-10L,2);		//将文件位置标记从文件末尾处向后退10个字节
/*ftell函数测定文件位置标记的当前位置,若函数出错(如不存在fp指向的文件),返回值为-1L*/
i=ftell(fp);			 //变量i存放文件位置标记
if(i==-1L) printf(″error\n″); 	//如果调用函数时出错,输出″error″

使用实例

/*
有一个磁盘文件,内有一些信息。要求第1次将它的内容显示在屏幕上,第2次把它复制到另一文件上。
*/
include<stdio.h>
int main()
{	char ch;
	FILE *fp1,*fp2;
	fp1=fopen("file1.dat","r");	//打开输入文件
	fp2=fopen("file2.dat","w");	//打开输出文件
	ch=getc(fp1);				//从file1.dat文件读入第一个字符
	while(!feof(fp1))			//当未读取文件尾标志
	{	putchar(ch);			//在屏幕输出一个字符
		ch=getc(fp1);			//再从file1.dat文件读入一个字符
	}
	putchar(10);				//在屏幕执行换行
	rewind(fp1);				//使文件位置标记返回文件开头
	ch=getc(fp1);				//从file1.dat文件读入第一个字符
	while(!feof(fp1))			//当未读取文件尾标志,feof是检测流上的文件结束符,如果文件结束返回非0值,否则返回0
	{	fputc(ch,fp2);			//向file2.dat文件输出一个字符
		ch=fgetc(fp1);			//再从file1.dat文件读入一个字符
	}
	fclose(fp1);fclose(fp2);
	return 0;
}

文件读写报错检测

ferror函数

在调用各种输入输出函数(如putc,getc,fread,fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。

ferror(fp); //如果ferror返回值为0(假),表示未出错;如果返回一个非零值,表示出错。

clearerr函数

假设在调用一个输入输出函数时出现错误,ferror函数值为一个非零值。此时应该立即调用clearerr(fp),使ferror(fp)的值变成0,以便再进行下一次的检测

clearerr(fp); 

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

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

相关文章

【LeetCode】1124. 表现良好的最长时间段

1124. 表现良好的最长时间段 题目描述 给你一份工作时间表 hours&#xff0c;上面记录着某一位员工每天的工作小时数。 我们认为当员工一天中的工作小时数大于 8 小时的时候&#xff0c;那么这一天就是「劳累的一天」。 所谓「表现良好的时间段」&#xff0c;意味在这段时间…

多线程下载工具axel的安装和使用

多线程下载工具axel的安装和使用 Axel是一个轻量级下载程序&#xff0c;它和其他加速器一样&#xff0c;对同一个文件建立多个连接&#xff0c;每个连接下载单独的文件片段以更快地完成下载。 Axel 支持 HTTP、HTTPS、FTP 和 FTPS 协议。它也可以使用多个镜像站点下载单个文件…

Springboot 使用插件 自动生成Mock单元测试 Squaretest

缘起 很多公司对分支单测覆盖率会有一定的要求&#xff0c;比如 单测覆盖率要达到 60% 或者 80%才可以发布。 有时候工期相对紧张&#xff0c;就优先开发功能&#xff0c;测试功能&#xff0c;然后再去补单元测试。 但是编写单元测试又比较浪费时间&#xff0c;有没有能够很大…

Spirng 痛苦源码学习(四)——AOP老大哥

文章目录前言一、探究AOP开始&#xff0c;判断导入的相关组件1.跟踪源码流程二、对切面中的增强方法进行增强1.源码的过程三、使用aop的目标类生成代理对象总结前言 Spring的两大特性&#xff1a;IOC&#xff1b;AOP。本篇仅以跟完Spring AOP相关源码为依据写的总结 一、探究A…

MySQL入门篇-MySQL高级窗口函数简介

备注:测试数据库版本为MySQL 8.0 这个blog我们来聊聊MySQL高级窗口函数 窗口函数在复杂查询以及数据仓库中应用得比较频繁 与sql打交道比较多的技术人员都需要掌握 如需要scott用户下建表及录入数据语句&#xff0c;可参考:scott建表及录入数据sql脚本 分析函数有3个基本组成…

matlab进行双目标定获取双目参数并打印教程

文章目录前言1.打开matlab进行双目标定2.获取想要的参数前言 在相同的标定算法和标定参数下&#xff0c;Python和Matlab的标定精度是相同的。因为标定精度主要取决于标定算法和标定参数的质量&#xff0c;而不是编程语言的选择。 不同的编程语言可能使用不同的库或实现细节&…

Hackergame 2020

3.Hackergame 2020 1.签到 url&#xff1a;http://202.38.93.111:10000/ 打开签到题页面&#xff0c;拖动滑杆&#xff0c;如果将滑杆滑动到最左边&#xff0c;提交 0&#xff0c;那么我们会得到成功的返回&#xff0c;但是没有 flag 尝试手动提交一些非整数的值&#xff0c…

HTML+CSS

HTML技术 什么是HTML Hyper Text Markup Language HTML&#xff1a;超文本标记语言&#xff0c;内部全部是一些不同的标记符号。 通俗的来讲&#xff1a;其实就是“网页”。 HTML 网页 网页的特点&#xff1a; 1、所有的网页都是通过【浏览器】来进行解析的。2、所有的网…

【MySQL】子查询

这里写自定义目录标题子查询1、子查询的基本使用2、 单行子查询2.1、单行比较查询2.2、HAVING 中的子查询2.3、CASE中的子查询3、多行子查询4、相关子查询5、EXISTS 与 NOT EXISTS关键字子查询 子查询指一个查询语句嵌套在另一个查询语句内部的查询&#xff0c;这个特性从MySQ…

算法笔记(四)—— 排序算法总结及链表

排序算法稳定性 值相同的元素排序结束后能否保持相对秩序不变。 冒泡排序具有稳定性&#xff08;相等时不交换&#xff09;。 插入排序具有稳定性。 归并排序具有稳定性&#xff08;merge的时候&#xff0c;相等时先拷贝左边的&#xff0c;小和问题让其丧失了稳定性&#x…

557. 反转字符串中的单词 III

给定一个字符串 s &#xff0c;你需要反转字符串中每个单词的字符顺序&#xff0c;同时仍保留空格和单词的初始顺序。 方法一&#xff1a;使用额外空间 思路与算法 开辟一个新字符串。然后从头到尾遍历原字符串&#xff0c;直到找到空格为止&#xff0c;此时找到了一个单词&a…

Http中你必须知道那点事

1, HTTP 1.1 简介 HTTP概念 HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 数据传输的规则指的是请求数据和响应数据需要按照指定的格式进行传输。如果想知道具体的格式&#xff0c;可以打开浏览器&#xf…

2、线程、块和网格

目录一、线程、块、网格概念二、代码分析2.1 打印第一个线程块的第一线程2.2 打印当前线程块的当前线程2.3 获取当前是第几个线程一、线程、块、网格概念 CUDA的软件架构由网格&#xff08;Grid&#xff09;、线程块&#xff08;Block&#xff09;和线程&#xff08;Thread&am…

Allegro如何设置导入Subdrawing可自由选择目录操作指导

Allegro如何设置导入Subdrawing可自由选择目录操作指导 用Allgro做PCB设计的时候,导入Subdrawing是非常常用的功能,在导入Subdrawing的时候,通常需要把Subdrawing文件放在需要导入PCB的相同目录下,不能自由选择,如下图 但是Allegro是支持自由选择目录的,只需按照下方的步…

Sphinx文档生成工具(一)

Sphinx在项目中部署应用 一、将安装的Sphinx发布 创建FindSphinx.cmake&#xff0c;这个名字只能是这个 find_program(SPHINX_EXECUTABLE NAMES sphinx-buildHINTS$ENV{SPHINX_DIR}HINTS ${SPHINX_ROOT}/binPATH_SUFFIXES binDOC "Sphinx documentation generator"…

企业为什么需要绩效管理软件?

随着经济的发展&#xff0c;企业的竞争日益激烈&#xff0c;“纸上谈兵”的绩效考核机制已经远远不能满足企业管理的需要。因此&#xff0c;企业绩效管理软件的重要性也日益凸显。 绩效管理软件可以提高企业管理效率、提高HR工作效率、提高员工工作能力。 今天就来给大家详细…

【C++】从0到1入门C++编程学习笔记 - 实战篇:演讲比赛流程管理系统

文章目录一、演讲比赛程序需求1.1 比赛规则1.2 程序功能1.3 程序效果图&#xff1a;二、项目创建2.1 创建项目2.2 添加文件三、创建管理类3.1创建文件3.2 头文件实现3.3 源文件实现四、菜单功能4.1 添加成员函数4.2 菜单功能实现4.3 测试菜单功能五、退出功能5.1 提供功能接口5…

RiproV2主题右侧美化右侧导航美化RiproV2主题右侧个人中心美化保持常驻

背景: RiproV2主题右侧美化右侧导航美化RiproV2主题右侧个人中心美化保持常驻 原样式没有文字只有图标,修改之后有文字,并且保持常驻在右侧,不随页面滚动而滚动 下面是楼主网站优化后的效果:

Linux中定时监控Tomcat服务器进程并在进程结束时重启Tomcat服务器

目录一、问题二、解决方法1、创建定时任务文件2、修改Tomcat的部分文件3、添加系统的定时调度4、执行monitor.sh文件5、查看脚本执行的日志文件一、问题 当我们的Tomcat配置完成后投入使用后&#xff0c;在用户使用一定时间后&#xff0c;Tomcat可能会出现一些问题导致进程结束…

mybatis-plus ---2

mybatis-plus插件 官网地址 分页插件 MyBatis Plus自带分页插件&#xff0c;只要简单的配置即可实现分页功能 配置并使用自带分页插件 Configuration MapperScan("com.itzhh.mapper")//可以将主类中的注解移到此处 public class MybatisPlusConfig {Beanpublic …