C语言----简单文件处理

news2024/9/28 7:16:43

        当大家学习过动态内存开辟后,那么我们就已经可以把内存的每一个地方使用了。但是大家有没有想过,我们现在是在自己电脑上打代码。以后工作了,自己写代码在自己电脑上,老板要是想要一份代码看看,或者你成为大能了,自己有一个很厉害的代码。别人想买你想卖,但是你代码只在自己电脑上。是不是说发个文件就好了呀。所以我们除了将这个整个代码发出去,我们还可以再编译器里面创建一个文件,然后发送,这样的话,只会发出这个文件的代码,不会波及其他的源代码。其实鄙人的讲述其实是不好的,反正大家了解一下嘛,技多不压身。后面肯定是会用上的。我这里就简单的列举几个我们刚开始使用文件处理的库函数吧。

 文件分类

        我们这里是了解关于文件的知识。首先要知道什么是文件吧。我们觉得简单理解的话,就是放在硬盘/磁盘里面的数据就是文件。嘿嘿这是个人的狭义之见。反正大家大概知道什么是文件就行了吧。我们这一小节是将讲文件的分类。文件分为:程序文件、数据文件

        那什么是程序文件嘞,包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。什么是数据文件嘞,文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。也就是说后缀是.c或者.obj,.exe的是程序文件。数据文件就是一堆数据。这个通俗易懂吧。

        好了,当我们知道什么是文件后,那么我们文件内容其实也是区分了的。比如我们都知道在C语言中存储中不改变什么的话,就是存储的二进制,因为0/1嘛最简单。但是不能只有1二进制啊。肯定还要有其他的。那么这个时候我们以前也学过的ascll码值就跳出来了。我们知道二进制无聊如何存储都只能是数字无法存储字符或者其他的但ascll码值就不一样了。可以存储字符和其他的特殊符号。所以我们可以根据数据的组织形式,数据⽂件被称为⽂本⽂件或者⼆进制⽂件。以ASCII字符的形式存储的⽂件就是文本⽂件。二进制文件就是以二进制存储的。

        我们以存储10000为例子,分别存储二进制形式与ascll形式。如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽ ⼆进制形式输出,则在磁盘上只占4个字节。然后我们可以在vs编译器里面点击文件的打开方式来选着二进制,大家可以在自己电脑上看一看。

1f9c254395b543728c2af74a1c9b7846.jpeg

3affc98f472c4dbdbf559129eecb5fb1.png

文件打开与关闭

       大家想一想我们文件打开与关闭,是不是像看书。我们看书开头需要一个打开书本的先前动作。那么等我们看完书一般还有一个关书的动作吧。

1.文件指针
文件系统中,关键的概念是“文件类型指针”,简称**“文件指针”**。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE。其实大家不用太在意这个的,我觉得大家只需要知道我们在文件处理的时候是有一个文件指针的。然后开头写的是FILE。然后这个指针指向的是文件就可以了。

0528f8d9b89041cc83bb3dc1e3104fb2.jpeg

        好了,我们知道了打开书要有一个动作然后关闭书还要有一个动作,那么我们打开和关闭是什么函数嘞。ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。当然大家一定要记得关闭不然一阵风吹过,不仅吹乱了我们的秀发还将我们以前“看书”的记录打乱了。

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );
         然后我们知道我们看书可以一张一张看也可以跳着看。并且我们C语言中文件读写有很多种方式,那么看一下,然后写着看一下都是如何使用的。
e36f808d27bf4dd5b73a8fd478a02e0c.png
        我们来看两个比较像的,r与w和rb与wb。
a1ea7651bfd24391a39aa2701138cfc6.png
619d9e2afdc645928e95800e889885f9.png
       我们可以看到这里我们开始没有创建yh.txt这个文件所以fopen只读的时候就报错说没有这个文件了但当我们接下来用w的时候编译器就没有报错了,反而是给我们创建了一个文件。所以这是普通的r与w的区别, 一个是看文件如果有的话就配合下面的代码做事情,如果没有的话就返回一个NULL。但w是没有文件的话就给你创建一个文件,然后配合下面的代码做事情。
       那我们再看看rb与wb吧 。
9f5aa5f2498a4758a920af2988e842b0.png
e3cd3e21b7e247b2ae844a63e510f4b8.png
      大家看到上面的照片后一个知道wb与rb就是二进制的读与写。并且在这里我写出来做什么事情的。但大家需要注意,做什么事情是有规定的吧读的话只能读,写的话只能写。不能说你明明写的rb但是却fputs。这样的话就是不对的。大家到这里可能就会想什么是fputs什么是fgets嘞。这个我们马上讲。我们这里先将这两个对比处理好。我们看到这里后不知道大家是否有想过,难道C语言的读写只有这几种了嘛。没有其他的了嘛。并不是的还有很多读与写的。但是我们现在常用的上面照片的那些。下面的这是是我们平常毕竟少用的。大家看看有个印象就可以了。
17ab0a973f794f9d9b7d143a4511ef28.jpeg

文件的顺序读写

       当我们知道文件的打开与关闭了后,那么我们就要了解如何做事情了是吧。而且在上面的图片中也出现过关于文件读写的库函数了。那么接下来我就将以这个为主要的讲述对象来给大家讲一讲。首先在这里,我们都是一页一页的看书的,就是如同我们打字都是一个一个打的,就算速度再快或者一次性打几个字,但是都是从第一个向后的。文件读写也是这样的,像我们鼠标有一个光标,打一个字向后一个。这就是标题的顺序读写。

        然后就是我在开头与大家将够的文件的输入与输出大体是不一样的,这里我就画了一个简单示意图,让大家理解的更清楚一些。

aea5c5d5220641bbbee08eef383c6011.png

        那么接下来我们就来看我们本章节重要的知识,读与写的库函数。那么我们还是先看一下关于文件顺序读写有哪些库函数吧。

582ce1c878fb42d6918045a14c5f0c46.png

       那么我们也还是讲两个比较特殊的fread与fwrite进行对比,然后其他的大家下来自己尝试一些,这样大家的印象更加深刻。

    fwrite:不知道大家有没有看懂我上面的这个代码,我是将数组arr里面的5个元素给输入到了文件yh.txt里面,大家可以看到下面的记事本,那个就是以二进制的形式存储进去的样子。我看肯定是看不懂的。反正大家只需要知道我们存储进去成功了就可以了。并且大家要注意上面fopen使用的是wb是输出不是输入哦。这里我们再提醒一下不要搞混了。我们用的输入就是输入,是输出就是输出。如果一点迷糊就,大家可以看看我上面的那张红色图片。

ba50b478a2254eeaa54fa18161fbf2bf.png

int main()
{
	int arr[] = { 1,2,3,4,5};
	FILE* pf = fopen("yh.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int sz = sizeof(arr[0]) / sizeof(arr[0]);
	fwrite(arr, sizeof(arr[0]), 5, pf);
	
	fclose(pf);
	pf = NULL;
	return 0;
}

        那么我们现在已经将arr数组里面的内容以二进制形式写到文件里面去了,那么我们是不是应该尝试将它拿出来让我们看看,是否正确啊。那么我们就看看上面的图片与fwrite相对应的是fread。一个输出那么后者就是输入了。好我们还是写一个代码大家来看看是怎么个事

       fread  ⼆进制输⼊ ⽂件输⼊流:就是二进制的输出。(写进的数组名,写进的元素大小,几个元素,开始打开文件的指针)

int main()
{
	int arr[] = { 1,2,3,4,5};
	int arr1[10] = { 0 };
	//FILE* pf = fopen("yh.txt", "wb");
	FILE* pf = fopen("yh.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	/*int sz = sizeof(arr[0]) / sizeof(arr[0]);
	fwrite(arr, sizeof(arr[0]), 5, pf);*/
	fread(arr1, sizeof(arr[0]), 5, pf);
	for (int a = 0; a < 5; a++)
	{
		printf("%d ", arr1[a]);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

        这里我就给大家讲了顺序读写中的两个比较特殊的库函数。其他的使用方法都大同小异,如果大家感兴趣的话,后面可以在编译器里面尝试一下。

fseek

       大家看到这里说明已经将上面的文件顺序读写看完了吧。那么我们肯定不是只想一个一个顺序读写吧,那么我们现在来讲一个文件偏移的库函数。fseek。首先我们要知道fseek有什么作用。它是我们指向的文件然后写偏移多少,光标就偏移多少。(光标就是我们前面说的鼠标打字)。下面的这个库函数的基本格式。

int fseek(FILE *stream, long int offset, int whence)
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • offset -- 这是相对 whence 的偏移量,以字节为单位。
  • whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
      那么我们写一段代码来看一下这个是如何使用的:我们用wb从新创建了一个文件夹,然后第一次给文件中写入了wxhn然后我们调整了光标的位置,再次存入了1314。当然肯定还是对比图来的直接那么我们接下里尝试不用fseek来写看看有什么效果。
int main()
{
	FILE * pFile;
	pFile = fopen("example.txt", "wb");
	fputs("wxhn      0", pFile);
	//fseek(pFile, 4, SEEK_SET);
	fputs("1314", pFile);
	fclose(pFile);
	return 0;
}

       不知道大家是否看出来了,我在上面的代码最后写了一个0,代表我在第一次存入的时候是以0结尾的,然后我在次存入的时候是从0后面开始存入的。这说明什么,我们第一次存入后光标在0后面,当我们在次存入的时候是在光标所在位置开始的。
        到这里不知道大家是否对fessk了解了,还有CUR,END。效果我已经写在上面了,大家感兴趣的话可以在后来写一下这样比我在这里写更加有作用。

ftell

        好了,当我们知道可以指定光标位置做事情了后,那么假如我们以后写代码写了几百行几千行的话,可能就忘了光标在那个位置了。那么这个时候我们就应该在想有没有什么库函数可以告诉我现在光标在哪里了。好这个时候ftell来了,这个就是告诉我们现在光标在那个位置。这里我们都不深究,一是鄙人本来实力也不是很强,怕班门弄斧了。二是鄙人觉得大体时间我们知道如何使用就可以了,太深层的话,等我们慢慢的成为大拿后自然也懂了。

long int ftell ( FILE * stream );
     大家可以看看下面的图片,因为ftell是返回一个long的函数,那么我们要事先创建一个变量来接收,然后打印。当然结果肯定是不会有错的,15这个结果是对的,这里大家不好数,大家可以在后面自己的编译器上看看答案是否正确。

 rewind

        不知道大家是否听过这样一句话,“你若回头,会发现我一直都在”那么我们在这里不能一直向前走啊,肯定要有回到梦最开始额地方啊。并且我们前面也只是说了一个fseek移动光标做事情啊。并没有一个直接回到开头的位置的库函数啊。那么我们的rewind就派上用场了。它的作用就是让光标回到文件的起始位置。

 void rewind ( FILE * stream );
       那么多少无益,我们直接上代码:我们可以看到我们是用循环将1~9存储到文件中,然后用rewind将光标返回打印的。希望大家可以理解。

文件读取结束的判定

       在我们使用读取文件的函数时,都讲解了其返回值,我们可以通过其返回值来判定对文件的读取是否成功(这里不再一一举例)。补充一个用来判断文件为什么结束读取的函数:

        feof函数 (包含在头文件stdio.h中)对于文件读取结束之后,我们可以使用feof函数来文件是为何而读取结束的:

          fgets 判断返回值是否为 NULL. 

         二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。例如: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);
}

         正确使用feof函数的例子:

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

补充

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

上面写的输入输出,与我们日常理解的输入输出不一样,这里的输入输入给我们(相当于我们平常的输出),那么这个里面的输出也是一样的了吧。所有输入流表示文件或者标注都是可以的

sprint:创建一个字符串数组,然后还有一个结构体赋初始值,使用sprintf的话会将这些内容装换位字符串并存储在写的那个字符串数组中。sprintf(接收数据的数组,传入数组中的内容),把格式化的数据装换为字符串

sscanf:把字符串装换为格式化的

5eeef10f10394bc0b3e06556c348da0c.jpeg

       好了以上就是鄙人想与大家分享的鄙见了。肯定还有很多错误和不足之处,希望大家可以不吝赐教,在评论区里面指出。

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

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

相关文章

Vue3气泡卡片(Popover)

效果如下图&#xff1a;在线预览 APIs 参数说明类型默认值必传title卡片标题string | slot‘’falsecontent卡片内容string | slot‘’falsemaxWidth卡片内容最大宽度string | number‘auto’falsetrigger卡片触发方式‘hover’ | ‘click’‘hover’falseoverlayStyle卡片样式…

cesium加载.tif格式文件

最近项目中有需要直接加载三方给的后缀名tif格式的文件 <script src"https://cdn.jsdelivr.net/npm/geotiff"></script> 或者 yarn add geotiff npm install geotiff 新建tifs.js import GeoTIFF, { fromBlob, fromUrl, fromArrayBuffer } from geotif…

智慧公厕四大核心能力,赋能城市公共厕所智能化升级

公共厕所是城市基础设施中不可或缺的一部分&#xff0c;但由于传统的公共厕所在建设与规划上&#xff0c;存在一定的局限性&#xff0c;导致环境卫生差、管理难度大、使用体验不佳等问题&#xff0c;给市民带来了很多不便。而智慧公厕作为城市智能化建设的重要组成部分&#xf…

【直播课】2024年PostgreSQL CM认证实战培训课程于4月27日开课!

课程介绍 了解关注开源技术&#xff0c;学习PG以点带面 Linux/Andriod&#xff08;操作系统&#xff09;、Apache/Tomcat&#xff08;应用服务器&#xff09;、OpenStack/KVM&#xff08;虚拟化&#xff09;、Docker/K8S&#xff08;容器化&#xff09;、Hadoop&#xff08;大…

全志R128 SDK HAL 模块开发指南——GPIO

GPIO 模块介绍 整个 GPIO 控制器由数字部分&#xff08;GPIO 和外设接口&#xff09;以及 IO 模拟部分&#xff08;输出缓冲&#xff0c;双下拉&#xff0c;引脚Pad&#xff09;组成。其中数字部分的输出可以通过 MUX 开关选择&#xff0c;模拟部分可以用来配置上下拉&#x…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之七 简单闪烁效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之七 简单闪烁效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之七 简单闪烁效果 一、简单介绍 二、简单闪烁效果实现原理 三、简单闪烁效果案例实现简单步骤 四、注意事项 一、简单…

C++超市商品管理系统

一、简要介绍 1.本项目为面向对象程序设计的大作业&#xff0c;基于Qt creator进行开发&#xff0c;Qt框架版本6.4.1&#xff0c;编译环境MINGW 11.2.0。 2.项目结构简介&#xff1a;关于系统逻辑部分的代码的头文件在head文件夹中&#xff0c;源文件在s文件夹中。与图形界面…

MySQL学习笔记------SQL(1)

关系型数据库&#xff08;RDBMS&#xff09; 建立在关系模型基础上&#xff0c;由多张相互连接的二维表组成的数据库 特点&#xff1a;使用表储存数据&#xff0c;格式统一&#xff0c;便于维护 使用SQL语言操作&#xff0c;标准统一&#xff0c;使用方便 SQL通用语法 SQL…

实力先锋!百望云入选“中国ToB行业影响力价值榜”

3月22日&#xff0c;2024「ToB头条行业大会」在北京大学中关新园举行。百望云实力入选“ToB行业年度榜单”&#xff0c;荣获“实力先锋企业”称号&#xff01;与百望云共同入围的企业还包括美团、腾讯云、网易云、WPS365、携程商旅等行业头部企业。 本次大会以“韧性生长、共话…

vue3+ts+element home页面侧边栏+头部组件+路由组件组合页面教程

文章目录 效果展示template代码script代码样式代码 效果展示 template代码 <template><el-container class"home"><el-aside class"flex" :style"{ width: asideDisplay ? 70px : 290px }"><div class"aside-left&q…

白酒:浓香型白酒的典型代表与特点

云仓酒庄的豪迈白酒作为白酒的品牌&#xff0c;具有一系列与众不同的特点和优势。下面云仓酒庄的豪迈白酒将从典型性、品质、口感和包装等方面深入分析白酒的特点&#xff0c;以及它如何体现浓香型白酒的魅力。 浓香型白酒是中国白酒的重要分支&#xff0c;以浓郁的香味和与众不…

Redis - 5k star! 一款简洁美观的 Redis 客户端工具~

项目简介 Tiny RDM 是一款现代化、轻量级的跨平台 Redis 桌面客户端&#xff0c;可在 Mac、Windows 和 Linux 系统上运行。初次打开 Tiny RDM&#xff0c;你会被它舒适的风格和配色所吸引&#xff0c;界面简约而不简单&#xff0c;功能齐全。 Tiny RDM 有着如下的功能特性 项…

进程与文件

目录 Linux的 > 和 >> 文件的本质 &#xff1a; 操作系统的系统调用函数 open&#xff1a; close&#xff1a;关闭文件 write&#xff1a; open的返回值&#xff1a; 操作系统视角中的“文件与进程之间的关系”&#xff1a; 从上图可以得知以下论点&#xff1a…

Linux:环境变量的特性及获取

目录 一、环境变量基本概念 1.1命令行参数 1.2常见环境变量 二、环境变量相关指令 创建本地变量 三、环境变量通常是具有全局属性的 一、环境变量基本概念 环境变量(environment variables)不是一个而是一堆&#xff0c;彼此之间其实没有关系。本质上是为了解决不同场景下…

Transformer的前世今生 day10(Transformer编码器

前情提要 ResNet&#xff08;残差网络&#xff09; 由于我们加更多层&#xff0c;更复杂的模型并不总会改进精度&#xff0c;可能会让模型与真实值越来越远&#xff0c;如下&#xff1a; 我们想要实现&#xff0c;加上一个层把并不会让模型变复杂&#xff0c;即没有它也没关系…

【JavaWeb】Day24.Web入门——SPringBootWeb入门

什么是SPring&#xff1f; 我们可以打开Spring的官网(Spring | Home)&#xff0c;去看一下Spring的简介&#xff1a;Spring makes Java simple。Spring的官方提供很多开源的项目&#xff0c;我们可以点击上面的projects&#xff0c;看到spring家族旗下的项目&#xff0c;按照流…

数据库是怎么做到事务回滚的呢?

数据库实现事务回滚的原理涉及到数据库管理系统&#xff08;DBMS&#xff09;如何维护事务的一致性和持久性。 基本原理&#xff1a; ACID属性&#xff1a;事务的原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Iso…

Elasticsearch从入门到精通-07ES底层原理学习

Elasticsearch从入门到精通-07ES底层原理和高级功能 &#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是程序员行走的鱼 &#x1f4d6; 本篇主要介绍和大家一块学习一下ES底层原理包括集群原理、路由原理、分配控制、分配原理、文档分析原理、文档并发安全原理以及一些高…

【热门话题】ECMAScript vs JavaScript:理解两者间的联系与区别

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 ECMAScript vs JavaScript&#xff1a;理解两者间的联系与区别1. ECMAScript&am…

创建一个vue3 + ts + vite 项目

vite 官网&#xff1a; https://cn.vitejs.dev/guide/ 兼容性注意 Vite 需要 Node.js 版本 18&#xff0c;20。然而&#xff0c;有些模板需要依赖更高的 Node 版本才能正常运行&#xff0c;当你的包管理器发出警告时&#xff0c;请注意升级你的 Node 版本。 安装项目 1. 使用n…