C语言:文件操作

简介: C语言:文件操作

文件

我们程序运行时,产生的临时数据会存放在内存中,一旦程序退出,数据就会丢失。如果我们想让电脑断电后,数据依然得以保存,那就需要把数据存到硬盘中

将数据写入文件,就可以把数据存到硬盘中

文件分类

在程序设计中,我们将文件分为:数据文件程序文件

程序文件

程序文件包括源文件.c,目标文件.o / .obj,可执行程序.exe

它们都是存储程序代码的文件,或者代码通过编译,链接后产生的文件。

数据文件

⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处理的就是磁盘上⽂件。

两者关系

如上图所示,大部分情况下,都是程序文件读取数据文件中的数据,或者向数据文件写入数据。


文件名

文件名用于标识一个文件,其由多部分组成,保证可以通过计算机中的唯一文件名找到一个确定的文件。

文件名 = 文件路径 + 文件名主干 + 文件名后缀

示例:

c:\code\test.txt

文件路径:c:\code\

文件名主干:test

文件名后缀:.txt


二进制文件

根据数据的组织形式,数据⽂件被称为⽂本⽂件或者⼆进制⽂件

文本文件

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

二进制文件

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

比如对于一个十进制数字10000,其有两种存储方式:

按照ASCII码值存储,最后存入了'1','0','0','0','0'五个字符,那么这就是一个文本文件。


按照一个int类型的数直接存储,这就是二进制文件;

概念

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输入输出操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念

程序员只需要向流中输入/提取数据,而与设备之间的数据交互,流会帮助我们完成


标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?

那是因为C语⾔程序在启动的时候,默认打开了3个流:

stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊。

stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯。

stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。

这是默认打开了这三个流,我们使⽤scanfprintf等函数就可以直接进⾏输⼊输出操作的


文件指针

当我们打开文件时,每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。

这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名FILE我们可以通过操纵这个FILE类型的结构体,来操控文件

大部分情况下,我们可以得到一个指向该结构体的指针FILE*,即文件指针,后续通过文件指针来操控文件,这也就是C语言操控文件的基本原理。

以上视图中,我们有三个指针pf1,pf2,pf3,它们都指向了一个FILE类型的文件信息区。而每个文件信息区都存储着一个文件的信息,我们后续就通过这三个指针来操控这三个文件。


文件的打开关闭

有了以上知识做铺垫,现在我们就可以在C语言中如何操控文件了。

文件在读写前,我们要现在程序中打开文件。

打开文件使用的函数是fopen

返回值:

返回值是一个FILE*的指针,也就是文件指针,后续通过这个指针操控文件

参数:

filename:即需要打开的文件的文件名

mode:打开的模式,需要用双引号

文件名很好理解,那么什么是打开模式?

打开模式分类如下:

模式 方式 含义 如果指定文件不存在
"r" 只读 为了输⼊数据,打开⼀个已经存在的⽂本⽂件 出错
"w" 只写 为了输出数据,打开⼀个⽂本⽂件,如果存在同名文件,则清空原先数据 创建一个新的文件
"a" 追加 向⽂本⽂件尾添加数据 创建一个新的文件
"rb" 只读 为了输⼊数据,打开⼀个⼆进制⽂件 出错
"wb" 只写 为了输出数据,打开⼀个⼆进制⽂件,如果存在同名文件,则清空原先数据 创建一个新的文件
"ab" 追加 向⼀个⼆进制⽂件尾添加数据 创建一个新的文件
"r+" 读写 为了读和写,打开⼀个⽂本⽂件 出错
"w+" 读写 为了读和写,建议⼀个新的⽂件,如果存在同名文件,则清空原先数据 创建一个新的文件
"a+" 读写 打开⼀个⽂件,在⽂件尾进⾏读写 创建一个新的文件
"rb+" 读写 为了读和写打开⼀个⼆进制⽂件 出错
"wb+" 读写 为了读和写,新建⼀个新的⼆进制⽂件 创建一个新的文件
"ab+" 读写 打开⼀个⼆进制⽂件,在⽂件尾进⾏读和写,如果存在同名文件,则清空原先数据 创建一个新的文件

“w”形式打开:

FILE * pFile = fopen ("myfile.txt", "w");

该打开方式是以写形式打开,也就是说我们打开文件后,可以向文件内写入数据。其有两个特性:

  1. 如果打开的文件不存在,那么会创建这个文件
  2. 如果打开的文件存在,那么会清空这个文件,从头开始写入

“r”形式打开:

FILE * pFile = fopen ("myfile.txt", "r");

该打开方式是以读形式打开,也就是说我们打开文件后,只能读取文件中的数据。其有以下特性:


如果打开的文件不存在,那么会发生错误


对于文件名:

我们先前都是直接输入文件名的主干 + 后缀来打开文件的。这种方式只能打开与源文件在同一目录下的文件。如果目标文件与源文件不在同一目录下,那么就需要用路径来打开了。

比如这样:

FILE * pFile = fopen ("C:\\user\\cp\\Desktop\\myfile.txt", "r");

要注意的是,路径分隔符\在C语言字符串中有转义的作用,需要用\\来表示一个\

其它的打开方式,在表中已经描述过功能,不再详细讲解了。


文件关闭使用的函数则是fclose

其用法很简单,就是把指向文件的FILE*指针传入即可。

FILE * pFile = fopen ("myfile.txt", "r");
fclose(pFile);

以上代码就完成了myfile.txt文件的打开和关闭。


文件读写

现在我们知道了如何打开和关闭文件,那么打开文件后,我们就需要对文件进行读取数据和写入数据了。

文件读写分为顺序读写随机读写



顺序读写

fputc

功能:向文件写入一个字符

参数:

character:要写入的字符

stream:目标流的指针

示例:

FILE* pf = fopen("test.txt", "w");
fputc('q', pf);

以上代码就完成了向test.txt文件中写入一个q的操作。


fgetc

功能: 从文件中读取一个字符

参数:

stream:目标流的指针

返回值:

当文件读取到末尾或者读取错误,返回EOF

示例:

FILE* pf = fopen("test.txt", "r");
char a = fputc(pf);

以上代码就完成了从test.txt中读取一个字符的功能。

特性:

当多次读取同一个文件,会从上一次读取的位置开始读取

所以我们可以根据这个特性,读取到整个文件的内容:

FILE* pf = fopen("test.txt", "r");
char a = fputc(pf);
while(a != EOF)
{
  printf("%c", a);
  a = fputc(pf)
}

只要a != EOF,那么就会一直读取下去,而下一次读取同一文件,会从下一个字符开始读取,所以可以读取到整个文件。


fputs

功能:向文件中写入一行字符

参数:

str:要写入的字符串

stream:目标流的指针

特性:

该函数完成的是一行的写入,所以在字符串结束时会自动追加一个 \n 换行

示例:

FILE* pf = fopen("test.txt", "w");
fputs("hello", pf);
fputs("world!", pf);

经过以上写入过程后,test.txt内部存放数据如下:

hello
world!

fgets

功能:读取一整行字符串

参数:

str:读取后字符串存储的位置

num:读取字符的数量

stream:指向目标流的指针

注意:如果读取的字数不足num,那么会中止读取

示例:

char arr[50] = { 0 };
FILE* pf = fopen("test.txt", "r");
fgets(arr, 20, pf);

以上代码就完成了读取test.txt中一行的字符,且不超过20个,并存入arr


fprintf

fprintf与先前的printf非常相似,其实它们的用法也几乎是一致的。

我们看看printf

printf("%d %c %s", 1, 'w', "hello");

该函数用于格式化地向屏幕输出字符串,其操作的流是stdout

fprintf也用于格式化地输出字符串,但是可以自己指定输出到哪一个流。也就是其第一个参数指定的流。

示例:

FILE* pf = fopen("test.txt", "w");
fprintf(pf, "%d %c %s", 1, 'w', "hello");


可以看到,除了多了一个流,其剩余的操作和printf完全一致。


fscanf

相似的,fscanf也就是可以从指定的流中,格式化地读取数据。

示例:

FILE* pf = fopen("test.txt", "r");
fscanf(pf, "%d %c %s", &a, &b, &c);

以上代码就是从test.txt文件中,按照intchar字符串的格式读取三个数据,存放到abc三个变量中。


sprintf

功能:得到格式化后的字符串

printf也非常相似,直接看用法:

char arr[100] = { 0 };
sprintf(arr, "%d %f %s", 5, 3.14, "hello");

此函数将格式化了字符串 "%d %f %s", 5, 3.14, "hello"并将其存放到arr中。


sscanf

功能:从格式化的字符串中提取数据

示例:

char* p = "5 3.140000 helloworld!";
sscanf(p, "%d %f %s", &a, &b, &c);

按照"%d %f %s"的格式,从字符串中读取了三个变量,并存放到变量中,变量存储的值如下:

a = 5;
b = 3.140000;
c = "helloworld!";

文件随机读写

先前的所有函数,都是从文件的头部开始往后读取的,而文件也是可以从任意位置开始读写,这种读写叫做随机读写

fseek

参数:

stream:目标文件指针

offset:指针偏移量

origin:开始偏移的位置

对于origin,其有三个指定值:

SEEK_SET:从头部开始偏移

SEEK_END:从末尾开始偏移

SEEK_CUR:从当前位置开始偏移

示例1:

FILE* pf = fopen("test.txt", "r");
fseek(pf, 5, SEEK_SET);
char c = fgetc(pf);

以上代码中,先使用fseek来改变文件指针指向的字符,SEEK_SET说明从文件头部开始偏移了5个字符。此时再使用fgetc读取到的就是第5个字符了。

示例2:

FILE* pf = fopen("test.txt", "r");
for(int i = 0; i <10; i++)
{
  fgetc(pf);  
}
fseek(pf, -3, SEEK_CUR);
fgetc(pf);  

以上代码,先执行了10次fgetc,此时文件指针指向第10个字符。接着使用了fseek,由于第三个参数为SEEK_CUR,所以会从当前字符也就是第10个字符开始偏移,偏移-3个地址,此时指向第7个字符。再使用fgetc读取到的就是第7个字符了。


ftell

功能:返回当前指针相对于起始地址的偏移量。


rewind

功能:让当前指针返回到起始位置


读取结束判定

feof

功能:当文件读取结束时,判断结束的原因是不是遇到文件末尾

返回值:

返回0:说明不是因为遇到文件末尾而结束

返回非0:说明是因为遇到文件末尾而结束


ferror

功能:当文件读取结束时,判断结束的原因是不是发生错误

返回值:

返回0:说明不是因为发生错误

返回非0:说明是因为发生了错误

相关文章
|
5天前
|
存储 编译器 C语言
关于文件操作---C语言
关于文件操作---C语言
|
5天前
|
存储 程序员 C语言
C语言-文件操作
C语言-文件操作
55 2
|
5天前
|
安全 算法 程序员
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
49 0
|
5天前
|
C语言
C语言文件操作
C语言文件操作
18 0
C语言文件操作
|
5天前
|
C语言
C语言文件操作
C语言文件操作
|
4天前
|
存储 程序员 C语言
C语言之详细讲解文件操作(抓住文件操作的奥秘)
C语言之详细讲解文件操作(抓住文件操作的奥秘)
10 0
|
5天前
|
存储 程序员 编译器
【C语言】深度探讨文件操作(一)
【C语言】深度探讨文件操作(一)
|
5天前
|
存储 C语言 C++
【C语言】文件与文件操作
前言:我们通过学习的技术可以完成计算与字符串处理,但程序结束之后就都消失了,这样岂不可惜。我们通过文件与数据持久化保存相关的基础知识。
12 0
|
5天前
|
存储 编译器 C语言
C语言中的文件操作指南
C语言中的文件操作指南
14 0
|
5天前
|
算法 C语言
【C 言专栏】C 语言文件操作的技巧与方法
【4月更文挑战第30天】本文介绍了C语言文件操作的关键技巧,包括文件的打开与关闭(使用`fopen`和`fclose`函数),读取(`fgetc`、`fgets`和`fread`)和写入(`fputc`、`fputs`和`fwrite`)操作。此外,还讨论了文件指针移动(`fseek`)、错误处理、文件权限和格式等问题。文中提供了一个简单的读写文件的示例,并提到了高级技巧如随机访问、文件缓冲和截断。掌握这些技能将有助于提升C语言编程中的文件处理能力。