文件操作详解(万字长文)

C语言文件操作

  • 一、为什么使用文件?
  • 二、文件分类
  • 三、文件的打开和关闭
  • 四、文件的顺序读写
    • 4.1fputc
    • 4.2fgetc
    • 4.3fputs
    • 4.4fgets
    • 4.5 fprintf
    • 4.6 fscanf
    • 4.7 fwrite
    • 4.8 fread
  • 五、文件的随机读写
    • 5.1 fseek
    • 5.2 ftell和rewind
    • 六、文件读取结束的判定
    • 七、文件缓冲区

一、为什么使用文件?

我们以创建变量举例,假设我们创建一个整型变量b,并且我们将它初始化为100,这样我们写的数据是储存在电脑的内存中的,然后我们退出程序,内存回收,数据就丢失了,等到再次运行程序的时候是看不到上一次程序的数据的。那我们能不能把它长久保存下来呢?这就需要用到文件,文件是保存在磁盘上的,使用磁盘(文件)来储存数据我们就可以对数据进行持久化储存。

二、文件分类

  • 程序文件:包括源程序文件(后缀为.c)目标文件(在windows环境下后缀为.obj)可执行程序(在windows环境下后缀为.exe)。
  • 数据文件:文件也不一定都是程序,也有可能文件中存放的是程序运行时读写的数据,这就是数据文件。

文件名:一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含三个部分:文件路径 + 文件名主干 + 文件后缀
例如:c:\code\test.c 中的c:\code\就是文件路径,test就是文件名主干,.c就是文件后缀。

二进制文件和文本文件
根据数据的组织形式,数据被称为二进制文件文本文件。
数据在内存中是以二进制的形式存储的,如果它不加转换的输出到外存的文件中,就是二进制文件,如果要求在外存的基础上以ASCll码的形式存储,这时候就需要在储存前转换,以ASCll码形式储存的文件就是文本文件

三、文件的打开和关闭

文件在读之前需要先打开文件,这时候你就需要一枚钥匙(fopen),在使用之后你还要关闭文件,这时候你需要一把锁(fclose)。

这两个函数都在#include <stdio.h>下,接下来我们来讲解这两个函数。
首先来看fopen的函数原型:

FILE* fopen(const char* filename,const char*mode);
//filename就是你要打开的文件名
//mode是你要以什么方式打开,像读、写等等

打开完成后fopen会返回一个FILE*类型的指针用于文件操作,如果打开失败fopen会返回空指针(NULL),所以通常我们需要对fopen的返回值进行判断。
关于文件的使用方式可以参照以下表格:

文件使用方式含义如果指定文件不存在
“r”(只读)为了输入数据,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)像文本文件末尾添加数据建立一个新的文件
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件

等等还有很多种操作,这里小编只列举了这几种方式来进行解释。
之后是fclose的函数原型

int fclose(FILE* stream);
//stream是指向文件的FILE*类型的指针

示例
首先我不创建text.c的文件:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.c", "r");if (pf == NULL){printf("打开失败");}else{printf("打开成功");}fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述
之后我再创建文件:
在这里插入图片描述
结果:
在这里插入图片描述

四、文件的顺序读写

既然我们已经可以打开关闭文件了,那总要做点什么吧,比如说往文件里面写一些数据,或者读一些数据,这时候就需要用到我们的函数,首先介绍顺序读写,之后介绍随机读写。

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

4.1fputc

函数原型:
在这里插入图片描述
这个函数的作用是向stream指向的文件中写东西。
注意:fputc是向文件中写数据,文件打开方式应该使用"w"
示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件for (int i = 'a';i < 'z';i++){fputc(i, pf);}fclose(pf);pf = NULL;return 0;
}

程序执行前:
在这里插入图片描述
程序执行后:
在这里插入图片描述

4.2fgetc

函数原型:
在这里插入图片描述
fgetc函数的作用是从文件中读取数据,我们可以把读取到的数据打印在屏幕上。

注意:此时是从文件中读取数据是只读的情况,所以文件打开方式应该选用“r”,当文件中的字符被逐个读完之后没有字符可读,或者一开始就没有字符可读时,fgetc函数会返回EOF(-1),所以我们可以以EOF来判断是否读取结束。

示例

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件int c = 0;while ((c = fgetc(pf)) != EOF){printf("%c ", c);}fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

4.3fputs

函数原型:
在这里插入图片描述
注意:向文件中写入字符串,打开文件方式用“w”

实例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件fputs("hello world\n", pf);fputs("hello new world\n",pf);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

4.4fgets

函数原型:
在这里插入图片描述
示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件char c[101];char s[101];fgets(c, 13, pf);fgets(s, 16, pf);printf("%s", c);printf("%s", s);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

使用fgets的注意事项:
1、当你要求它读取8个字符的时候他其实会从文件中读取7个字符剩下的那个字符空间他会用来储存‘\0’。
2、不知道大家有没有发现我的打印函数里面都没有添加换行符,但打印出来却换行了,这是因为fgets读取到了文件行末尾的换行符。

4.5 fprintf

函数原型:
在这里插入图片描述
首先函数的第一个参数是指向文件的FILE*指针,第二个参数是传入数据的形式,像%d、%f这些。
示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件fprintf(pf, "%d %lf %c", 100, 3.14, 'a');fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

4.6 fscanf

函数原型:
在这里插入图片描述
示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}int n;double d;char c;//读文件fscanf(pf, "%d %lf %c", &n,&d,&c);printf("%d\n", n);printf("%f\n", d);printf("%c\n", c);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

4.7 fwrite

函数原型:
在这里插入图片描述

其中ptr指针指向的是要传文件数据的数组,size是一次传送的字节大小,count是传送的次数,stream是FILE*类型的指针。此时文件的打开方式应该是“wb”。

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "wb");if (pf == NULL){perror("fopen");return 1;}//写文件int a[] = { 1,2,3 };fwrite(a,sizeof(a[0]),3,pf);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述
当我们以二进制的形式存入数据的时候,它给出的结果我们已经识别不出来了,我们转化为2进制再看一下:
在这里插入图片描述
以二进制的方式打开我们发现的确储存了1,2,3,而且是以16进制的形式储存的和内存的储存形式相同。

4.8 fread

函数原型:
在这里插入图片描述

其中ptr指针指向的是要存放数据的数组,size是从文件读取的字节大小,count是读取的个数,stream是FILE*类型的指针。此时文件的打开方式应该是“rb”。

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "rb");if (pf == NULL){perror("fopen");return 1;}//读文件int arr[4] = { 0 };for (int i = 0;i < 3;i++){fread(arr + i, sizeof(arr[0]), 1, pf);printf("%d ", arr[i]);}fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

五、文件的随机读写

5.1 fseek

函数原型:
在这里插入图片描述
第一个参数是一个FILE*类型的指针,第二个参数是偏移量,第三个参数是参照系。那这个具体是什么意思呢?就是选择一个参照系,比如我选择文件开头,然后偏移量选择3,那就是从文件中第三个字符开始读取的意思。

关于参照系这里有一个表格,它一共有三个取值:
在这里插入图片描述
SEEK_SET:文件的开始位置
SEEK_CUR:光标的当前位置
SEEK_END:文件末尾位置

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件char arr[10];fseek(pf, -11, SEEK_END);arr[0] = fgetc(pf);fputc(arr[0], stdout);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述
另外两个origin取值也是相同的用法。

5.2 ftell和rewind

ftell的函数原型:
在这里插入图片描述
它只有一个参数就是文件指针,它的作用是返回光标当前位置。

rewind的函数原型:
在这里插入图片描述
它也只有一个参数就是文件指针,它的作用是让光标回到文件的起始位置。

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件char arr[10];fseek(pf, -11, SEEK_END);arr[0] = fgetc(pf);fputc(arr[0], stdout);long int n = ftell(pf);printf("\n%ld\n", n);rewind(pf);n=ftell(pf);printf("%ld", n);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

六、文件读取结束的判定

C语言中有一个函数是feof,它的作用是当文件读取结束的时候,判断读取的原因是不是遇到文件尾而结束。
注意:在文件读取的过程中不能用feof函数的返回值直接判断文件是否结束。
它的函数原型:
在这里插入图片描述
那如何判断文件是否读取结束呢?
对于文本文件
例如:fgetc判断返回值是不是EOF,fgets判断返回值是不是NULL。
对于二进制文件
二进制文件是否读取结束,是判断返回值是不是小于实际要读的个数。
例如:fread判断返回值是否小于实际要读的个数。

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件int c;while ((c = fgetc(pf)) != EOF){putchar(c);}if (ferror(pf))//判断是不是异常结束{printf("\nI/O error when reading");}else if (feof(pf))//判断是不是正常结束{printf("\nEnd of file reached successfully");}fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

七、文件缓冲区

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

例如:
当我们输入数据时,系统会开辟一个输入缓冲区,假设这个缓冲区的大小是固定的,我们输入数据时它会等到缓冲区被充满后在一起送到磁盘上,输出缓冲区也是这样。这样就大大解放了程序的空间和时间,使计算机能够同时处理更多的事。
在这里插入图片描述

总结
以上就是全部的今天博客内容,内容稍微有点多,读者朋友可以点个关注,博主后续还会给大家带来更多的优质内容~
另外,如果有什么问题,可以在评论区留言,博主看到后,会一一回复。
好了,让我们下期博客再见!
(~ ̄▽ ̄)~

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

突破极限!蓝耘通义万相2.1引爆AI多模态新纪元——性能与应用全方位革新

云边有个稻草人-CSDN博客 目录 一、 引言 二、 蓝耘通义万相2.1版本概述 三、 蓝耘通义万相2.1的核心技术改进 【多模态数据处理】 【语音识别与文本转化】 【自然语言处理&#xff08;NLP&#xff09;改进】 【跨平台兼容性】 四、 蓝耘注册 部署流程—新手也能轻松…

力扣-股票买入问题

dp dp元素代表最大利润 f[j][1] 代表第 j 次交易后持有股票的最大利润。在初始状态&#xff0c;持有股票意味着你花钱买入了股票&#xff0c;此时的利润应该是负数&#xff08;扣除了买入股票的成本&#xff09;&#xff0c;而不是 0。所以&#xff0c;把 f[j][1] 初始化为负…

ubuntu22.04本地部署OpenWebUI

一、简介 Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台&#xff0c;旨在完全离线运行。它支持各种 LLM 运行器&#xff0c;如 Ollama 和 OpenAI 兼容的 API&#xff0c;并内置了 RAG 推理引擎&#xff0c;使其成为强大的 AI 部署解决方案。 二、安装 方法 …

Unity开发——CanvasGroup组件介绍和应用

CanvasGroup是Unity中用于控制UI的透明度、交互性和渲染顺序的组件。 一、常用属性的解释 1、alpha&#xff1a;控制UI的透明度 类型&#xff1a;float&#xff0c;0.0 ~1.0&#xff0c; 其中 0.0 完全透明&#xff0c;1.0 完全不透明。 通过调整alpha值可以实现UI的淡入淡…

LVGL直接解码png图片的方法

通过把png文件解码为.C文件&#xff0c;再放到工程中的供使用&#xff0c;这种方式随时速度快&#xff08;应为已经解码&#xff0c;代码中只要直接加载图片数据显示出来即可&#xff09;&#xff0c;但是不够灵活&#xff0c;适用于哪些简单又不经常需要更换UI的场景下使用。如…

【算法day5】最长回文子串——马拉车算法

最长回文子串 给你一个字符串 s&#xff0c;找到 s 中最长的 回文 子串。 https://leetcode.cn/problems/longest-palindromic-substring/description/ 算法思路&#xff1a; class Solution { public:string longestPalindrome(string s) {int s_len s.size();string tmp …

JavaWeb-HttpServletRequest请求域接口

文章目录 HttpServletRequest请求域接口HttpServletRequest请求域接口简介关于请求域和应用域的区别 请求域接口中的相关方法获取前端请求参数(getParameter系列方法)存储请求域名参数(Attribute系列方法)获取客户端的相关地址信息获取项目的根路径 关于转发和重定向的细致剖析…

Dify 本地部署教程

目录 一、下载安装包 二、修改配置 三、启动容器 四、访问 Dify 五、总结 本篇文章主要记录 Dify 本地部署过程,有问题欢迎交流~ 一、下载安装包 从 Github 仓库下载最新稳定版软件包,点击下载~,当然也可以克隆仓库或者从仓库里直接下载zip源码包。 目前最新版本是V…

css错峰布局/瀑布流样式(类似于快手样式)

当样式一侧比较高的时候会自动换行&#xff0c;尽量保持高度大概一致&#xff0c; 例&#xff1a; 一侧元素为5&#xff0c;另一侧元素为6 当为5的一侧过于高的时候&#xff0c;可能会变为4/7分部dom节点 如果不需要这样的话删除样式 flex-flow:column wrap; 设置父级dom样…

Docker入门篇1:搜索镜像、拉取镜像、查看本地镜像列表、删除本地镜像

大家好我是木木&#xff0c;在当今快速发展的云计算与云原生时代&#xff0c;容器化技术蓬勃兴起&#xff0c;Docker 作为实现容器化的主流工具之一&#xff0c;为开发者和运维人员带来了极大的便捷 。下面我们一起开始入门第一篇&#xff1a;搜索镜像、拉取镜像、查看本地镜像…

利用pdf.js+百度翻译实现PDF翻译,创建中文PDF

基于JavaScript的PDF文档解析与智能翻译系统开发实践 一、功能预览 1.1 PDF加载 1.2 PDF翻译 二、系统架构设计 2.1 PDF智能翻译系统架构设计 层级模块名称功能描述技术实现呈现层Canvas渲染器PDF文档可视化渲染PDF.js + 动态视口计算 + 矩阵变换

虚函数和虚表的原理是什么?

虚函数是一个使用virtual关键字声明的成员函数&#xff0c;在基类中声明虚函数&#xff0c;在子类中可以使用override重写该函数。虚函数根据指针或引用指向的实际对象调用&#xff0c;实现运行时的多态。 虚函数表&#xff08;虚表&#xff09;是一个用于存储虚函数地址的数组…

运行OpenManus项目(使用Conda)

部署本项目需要具备一定的基础&#xff1a;Linux基础、需要安装好Anaconda/Miniforge&#xff08;Python可以不装好&#xff0c;直接新建虚拟环境的时候装好即可&#xff09;&#xff0c;如果不装Anaconda或者Miniforge&#xff0c;只装过Python&#xff0c;需要确保Python是3.…

vulnhub靶场之【digitalworld.local系列】的vengeance靶机

前言 靶机&#xff1a;digitalworld.local-vengeance&#xff0c;IP地址为192.168.10.10 攻击&#xff1a;kali&#xff0c;IP地址为192.168.10.6 kali采用VMware虚拟机&#xff0c;靶机选择使用VMware打开文件&#xff0c;都选择桥接网络 这里官方给的有两种方式&#xff…

纯html文件实现目录和文档关联

目录结构 效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>项目结题报告</title><style lang"scss">::-webkit-scrollbar {width: 6px;height: 6px;}::-webkit-scro…

计算机网络——交换机

一、什么是交换机&#xff1f; 交换机&#xff08;Switch&#xff09;是局域网&#xff08;LAN&#xff09;中的核心设备&#xff0c;负责在 数据链路层&#xff08;OSI第二层&#xff09;高效转发数据帧。它像一位“智能交通警察”&#xff0c;根据设备的 MAC地址 精准引导数…

Primer - 自适应学习,AI学习工具

android Primer - 自适应学习 链接&#xff1a;https://pan.xunlei.com/s/VOKv1kIghHXGSbjg3PIZnhWHA1?pwdwfn6# 【软件说明】&#xff1a;采用先进的自适应学习算法&#xff0c;能够迅速识别您当前的知识水平&#xff0c;并推荐新的学习主题。经过初步评估后&#xff0c;您…

【Vue3 Element UI - Plus + Tyscript 实现Tags标签输入及回显】

Vue3 Element Plus TypeScript 实现 Tags 标签输入及回显 在开发后台管理系统或表单页面时&#xff0c;动态标签&#xff08;Tags&#xff09; 是一个常见的功能需求。用户可以通过输入框添加标签&#xff0c;并通过关闭按钮删除标签&#xff0c;同时还需要支持标签数据的提…

程序员学习强化学习之基本概念的数学表达

基本概念 迷宫游戏为例 状态(State)&#xff1a;S {s1, . . . , s9} 行动(Action)&#xff1a;A {a1, . . . , a5} 状态转移(State transition)&#xff1a; 奖励(Reward)&#xff1a;r(s, a) 是 s和a的函数 序列(Trajectories) 策略1的序列&#xff1a; 策略2的序列&…

达梦数据库查看字符集编码

select SF_GET_UNICODE_FLAG(); 返回 0 代表数据库字符集编码为 GB18030 1 代表数据库字符集编码为 UTF-8 2 代表数据库字符集编码为韩文字符集 EUC-KR