技术标签: R语言怎么写积分 R 语言怎么保存工作目录到当前路径 r语言怎么把txt数据变成一个Rdata格式
前言
文件的打开和关闭
读写文件的不同方法
在文件中移动
文件的重命名和删除
第二部分第八课预告
上一课 C语言探索之旅 | 第二部分第六课:创建你自己的变量类型 之后,我们来学习很常用的文件读写。
我们学过了这么多变量的知识,已经知道变量实在是很强大的,可以帮助我们实现很多事情。
变量固然强大,还是有缺陷的,最大的缺陷就是:不能永久保存。
因为 C语言的变量储存在内存中,在你的程序退出时就被清除了,下次程序启动时就不能找回那个值了。
“蓦然回首,那人不在灯火阑珊处…”
“今天的你我,
怎样重复昨天的故事?
这一张旧船票,
还能否登上你的破船?”不能够啊,“涛声不能依旧”啊…
如果这样的话,我们如何在 C语言编写的游戏中保存游戏的最高分呢?怎么用 C语言写一个退出时依然保存文本的文本编辑器呢?
幸好,在 C语言中我们可以读写文件。这些文件会储存在我们电脑的硬盘上,就不会在程序退出或电脑关闭时被清除了。
为了实现文件读写,我们就要用到迄今为止我们所学过的知识:
指针,结构体,字符串,等等。
也算是复习吧。
为了读写文件,我们需要用到定义在 stdio.h 这个标准库头文件中的一些函数,结构,等。
是的,就是我们所熟知的 stdio.h,我们的“老朋友” printf 和 scanf 函数也是定义在这个头文件里。
下面按顺序列出我们打开一个文件,进行读或写操作所必须遵循的一个流程:
调用“文件打开”函数 fopen(f 是 file(表示“文件”)的首字母;open 表示“打开”),返回一个指向该文件的指针。
检测文件打开是否成功,通过第 1 步中 fopen 的返回值(文件指针)来判断。如果指针为 NULL,则表示打开失败,我们需要停止操作,并且返回一个错误。
如果文件打开成功(指针不为 NULL),那么我们就可以接着用 stdio.h 中的函数来读写文件了。
一旦我们完成了读写操作,我们就要关闭文件,用 fclose(close 表示“关闭”)函数。
首先我们来学习如何使用 fopen 和 fclose 函数,之后我们再学习如何读写文件。
函数 fopen 的原型是这样的:
FILE* fopen(const char* fileName, const char* openMode);
不难看出,这个函数接收两个参数:
fileName:文件名(name 表示“名字”)。是一个字符串类型,而且是 const,意味着不能改变其值。
openMode:打开方式(open 表示“打开”,mode 表示“方式”)。表明我们打开文件之后要干什么的一个指标。只读、只写、读写,等等。
这个函数的返回值,是 FILE *
,也就是一个 FILE(file 表示“文件”)指针。
FILE 定义在 stdio.h 中。有兴趣的读者可以自己去找一下 FILE 的定义。
我们给出 FILE 的一般定义:
typedef
可以看到 FILE 是一个结构体(struct),里面有 7 个变量。当然我们不必深究 FILE 的定义,只要会使用 FILE 就好了,而且不同操作系统对于 FILE 的定义不尽相同。
细心的读者也许会问:“之前不是说结构体的名称最好是首字母大写么,为什么 FILE 这个结构体每一个字母都是大写呢?怎么和常量的命名方式一样呢?”
好问题。其实我们之前建议的命名方式(对于结构体,首字母大写,例如:StructName)只是一个“规范”(虽然大多数程序员都喜欢遵循),并不是一个强制要求。
这只能说明编写 stdio.h 的前辈并不一定遵循这个“规范”而已。当然,这对我们并没什么影响。
以下列出几种可供使用的 openMode :
r
:只读。r 是 read(表示“读”)的首字母。这个模式下,我们只能读文件,而不能对文件写入。文件必须已经存在。
w
:只写。w 是 write(表示“写”)的首字母。这个模式下,只能写入,不能读出文件的内容。如果文件不存在,将会被创建。
a
:追加。a 是 append(表示“追加”)的首字母。这个模式下,从文件的末尾开始写入。如果文件不存在,将会被创建。
r+
:读和写。这个模式下,可以读和写文件,但文件也必须已经存在。
w+
:读和写。预先会删除文件内容。这个模式下,如果文件存在且内容不为空,则内容首先会被清空。如果文件不存在,将会被创建。
a+
:读写追加。这个模式下,读写文件都是从文件末尾开始。如果文件不存在,将会被创建。
上面所列的模式,其实还可以组合上 b
这个模式。b 是 binary 的缩写,表示“二进制”。对于上面的每一个模式,如果你添加 b
后,会变成 rb
,wb
,ab
,rb+
,wb+
,ab+
),该文件就会以二进制模式打开。不过二进制的模式一般不是那么常用。
一般来说,r
,w
和 r+
用得比较多。w+
模式要慎用,因为它会首先清空文件内容。当你需要往文件中添加内容时,a
模式会很有用。
下面的例子程序就以 r+
(读写)的模式打开文件:
#include
于是,file 成为了指向 test.txt 文件的一个指针。
你会问:“我们的 test.txt 文件位于哪里呢?”
text.txt 文件和可执行文件位于同一目录下。
“文件一定要是 .txt 结尾的吗?”
不是,完全由你决定文件的后缀名。你大可以创建一个文件叫做 xxx.level,用于记录游戏的关卡信息。
“文件一定要和可执行文件在同一个文件夹下么?”
也不是。理论上可以位于当前系统的任意文件夹里,只要在 fopen 函数的文件名参数里指定文件的路径就好了,例如:
file = fopen(
这样,文件 test.txt 就是位于当前目录的文件夹 folder 里。这里的 folder/test.txt
称为“相对路径”。
我们也可以这样:
file = fopen(
这里的 /home/user/folder/test.txt
是“绝对路径”。
在调用 fopen 函数尝试打开文件后,我们需要检测 fopen 的返回值,以判断打开是否成功。
检测方法也很简单:如果 fopen 的返回值为 NULL,那么打开失败;如果不为 NULL,那么表示打开成功。示例如下:
#include
记得每次使用 fopen 函数时都要对返回值作判断,因为如果文件不存在或者正被其他程序占用,那可能会使当前程序运行失败。
close 表示“关闭”。
如果我们成功地打开了一个文件,那么我们就可以对文件进行读写了(读写的操作我们下一节再详述)。
如果我们对文件的操作已经结束,那么我们应该关闭这个文件,这样做是为了释放占用的文件指针。
我们需要调用 fclose 函数来实现文件的关闭,这个函数可以释放内存,也就是从内存中删除你的文件(指针)。
函数原型:
int fclose(FILE* pointerOnFile);
这个函数只有一个参数:指向文件的指针。
函数的返回值(int)有两种情况:
0 :当关闭操作成功时。
EOF(是 End Of File 的缩写,表示“文件结束”。一般等于 -1):如果关闭失败。
示例如下:
#include
现在,我们既然已经知道怎么打开和关闭文件了,接下来我们就学习如何对文件进行读出和写入吧。
我们首先学习如何写入文件(相比读出要简单一些),之后我们再看如何从文件读出。
用于写入文件的函数有好几个,我们可以根据情况选择最适合的函数来使用。
我们来学习三个用于文件写入的函数:
fputc:在文件中写入一个字符(一次只写一个)。是 file put character 的缩写。put 表示“放入”,character 表示“字符”。
fputs:在文件中写入一个字符串。是 file put string 的缩写。string 表示“字符串”。
fprintf:在文件中写入一个格式化过的字符串,用法与 printf 是几乎相同的,只是多了一个文件指针。
此函数用于在文件中一次写入一个字符。
函数原型:
int fputc(int character, FILE* pointerOnFile);
这个函数包含两个参数:
character:int 型变量,表示要写入的字符。我们也可以直接写 'A' 这样的形式,之前 ASCII 那节的知识点没有忘吧。
pointerOnFile:指向文件的指针。
函数返回 int 值。如果写入失败,则为 EOF;否则,会是另一个值。
示例:
#include
上面的程序用于向 test.txt 文件写入字符 'A'。
这个函数和 fputc 类似,区别是 fputc 每次是写入一个字符,而 fputs 每次写入一个字符串。
函数原型:
int fputs(const char* string, FILE* pointerOnFile);
类似地,这个函数也接受两个参数:
string:要写入的字符串。
pointerOnFile:指向文件的指针。
如果出错,函数返回 EOF;否则,返回不同于 EOF 的值。
示例:
#include
这个函数很有用,因为它不仅可以向文件写入字符串,而且这个字符串是可以由我们来格式化的。用法其实和 printf 函数类似,就是多了一个文件指针。
函数原型:
int fprintf(FILE *stream, const char *format, ...)
示例:
#include
我们可以用与写入文件时类似名字的函数,只是略微修改了一些,也有三个:
fgetc:读出一个字符。是file get character 的缩写。get 表示“获取,取得”。
fgets:读出一个字符串。是 file get string 的缩写。
fscanf:与 scanf 的用法类似,只是多了一个文件指针。scanf 是从用户输入读取,而 fscanf 是从文件读取。
这次介绍这三个函数我们会简略一些,因为如果大家掌握好了前面那三个写入的函数,那这三个读出的函数是类似的。只是操作相反了。
首先给出函数原型:
int fgetc(FILE* pointerOnFile);
函数返回值是读到的字符。如果不能读到字符,那会返回 EOF。
但是如何知道我们从文件的哪个位置读取呢?是第三个字符处,还是第十个字符处呢?
其实,在我们读取文件时,有一个“游标”(cursor),会跟随移动。
这当然是虚拟的游标,你不会在屏幕上看到它。你可以想象这个游标和你用记事本编辑文件时的闪动的光标类似。这个游标指示你当前在文件中的位置。
之后的小节,我们会学习如何移动这个游标,使其位于文件中特定的位置。可以是开头,也可以是第 7 个字符处。
fgetc 函数每读入一个字符,这个游标就移动一个字符长度。我们就可以用一个循环来读出文件所有的字符。例如:
#include
此函数每次读出一个字符串,这样可以不必每次读一个字符(有时候效率太低)。
这个函数每次最多读取一行,因为它遇到第一个 '\n'(换行符)会结束读取。所以如果我们想要读取多行,需要用循环。
插入一点回车符和换行符的知识:
关于“回车”(carriage return)和“换行”(line feed)这两个概念的来历和区别。
在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打 10 个字符。
但是它有一个问题,就是打完一行换行的时候,要用去 0.2 秒,正好可以打两个字符。要是在这 0.2 秒里面,又有新的字符传过来,那么这个字符将丢失。
于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。
后来,计算机被发明了,这两个概念也就被搬到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。在 Unix/Linux 系统里,每行结尾只有“”,即 "\n";在 Windows 系统里面,每行结尾是“”,即 "\n\r";在 macOS 系统里,每行结尾是“”,即 "\r"。
一个直接后果是,Unix/Linux/macOS 系统下的文件在Windows里打开的话,所有文字会变成一行;而 Windows 里的文件在 Unix/Linux/macOS 下打开的话,在每行的结尾可能会多出一个^M
符号。
Linux 中遇到换行符会进行“回车 + 换行”的操作,回车符反而只会作为控制字符显示,不发生回车的操作。
而 Windows 中要“回车符 + 换行符”才会实现“回车+换行",缺少一个控制符或者顺序不对都不能正确的另起一行。
函数原型:
char* fgets(char* string, int characterNumberToRead, FILE* pointerOnFile);
示例:
#include
这里,我们的 MAX_SIZE 足够大(1000),保证可以容纳下一行的字符数。所以遇到 '\n' 我们就停止读取,因此以上代码的作用就是读取文件中的一行字符,并将其输出。
那我们如何能够读取整个文件的内容呢?很简单,加一个循环。
如下:
#include
此函数的原理和 scanf 是一样的。负责从文件中读取规定样式的内容。
函数原型:
int fscanf(FILE *stream, const char *format, ...)
示例:
例如我们创建一个 test.txt 文件,在里面输入三个数:23, 45, 67。
输入的形式可以是类似下面这样:
每个数之间有空格
每个数之间换一行
#include
运行输出:
最佳得分是:23, 45, 67
前面我们提到了虚拟的“游标”,现在我们仔细地来学习一下。
每当我们打开一个文件的时候,实际上都存在一个“游标”,标识你当前在文件中所处的位置。
你可以类比我们的文本编辑器,每次你在文本编辑器(例如记事本)里面输入文字的时候,不是有一个游标(光标)可以到处移动么?它指示了你在文件中的位置,也就是你下一次输入会从哪里开始。
总结来说,游标系统使得我们可以在文件中指定位置进行读写操作。
我们介绍三个与文件中游标移动有关的函数:
ftell:告知目前在文件中哪个位置。tell 表示“告诉”。
fseek:移动文件中的游标到指定位置。seek 表示“探寻”。
rewind:将游标重置到文件的开始位置(这和用 fseek 函数来使游标回到文件开始位置是一个效果)。rewind 表示“转回”。
这个函数使用起来非常简单,它返回一个 long 型的整数值,标明目前游标所在位置。函数原型是:
long ftell(FILE* pointerOnFile);
其中,pointerOnFile 这个指针就是文件指针,指向当前文件。
相信不必用例子就知道如何使用了吧。
函数原型为:
int fseek(FILE* pointerOnFile, long move, int origin);
此函数能使游标在文件(pointerOnFile 指针所指)中从位置(origin 所指。origin 表示“初始”)开始移动一定距离(move 所指。move 表示“移动”)。
move 参数:可以是一个正整数,表明向前移动;0,表明不移动;或者负整数,表明回退。
origin 参数:它的取值可以是以下三个值(#define
所定义的常量)中的任意:
SEEK_SET
:文件开始处。SET 表示“设置”。
SEEK_CUR
:游标当前所在位置。CUR 是 current(表示“当前”)的缩写。
SEEK_END
:文件末尾。END 表示“结尾”。
来看几个具体使用实例吧:
// 这行代码将游标放置到距离文件开始处 5 个位置的地方
这个函数的作用就相当于使用 fseek 来使游标回到 0 的位置
void rewind(FILE* pointerOnFile);
相信使用难不倒大家吧,看函数原型就一目了然了。和 fseek(file, 0, SEEK_SET);
是一个效果。
我们来学习两个简单的函数,以结束这次的课程:
rename 函数:重命名一个文件(rename 表示“重命名”)。
remove 函数:删除一个文件(remove 表示“移除”)。
这两个函数的特殊之处就在于,不同于之前的一些文件操作函数,它们不需要文件指针作为参数,只需要把文件的名字传给这两个函数就够了。
函数原型:
int rename(const char* oldName, const char* newName);
oldName 就是文件的“旧名字”,而 newName 是文件的“新名字”。
如果函数执行成功,则返回 0;否则,返回非零的 int 型值。
以下是一个使用的例子:
int main(int argc, char *argv[]){
很简单吧。
函数原型:
int remove(const char* fileToRemove);
fileToRemove 就是要删除的文件名。
注意:remove 函数要慎用,因为它不会提示你是否确认删除文件。
文件是直接从硬盘被永久删除了,也不会先移动至垃圾箱。
想要再找回被删除的文件就只能借助一些特殊的软件了,但是恢复过程可能没那么容易,也不一定能够成功。
实例:
int main(int argc, char *argv[]){
今天的课就到这里,一起加油吧!
下一课:C语言探索之旅 | 第二部分第八课:动态分配
作者:谢恩铭
出处:公众号「程序员联盟」
原文链接:https://www.jianshu.com/p/4adb95073745
转载请注明出处,谢谢合作!转载授权请加我微信 frogoscar
喜欢本文的朋友,欢迎关注公众号 程序员联盟,收看更多精彩内容
点个[在看],是对我最大的支持!
文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大
文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码
文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版
文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗
文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程
文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0
文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader
文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型
文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写
文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录
文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点
文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文