C语言教程——文件处理(1)

目录

前言

二、什么是文件

2.1文件的概念

2.2程序文件

2.3数据文件

2.4文件名

2.5二进制文件和文本文件

三、文件操作

3.1文件指针

3.2文件的打开与关闭

四、文件的顺序读写

4.1fgetc

4.2fputc

4.3fputs

4.4fgets

总结


前言

我们知道电脑上有许许多多的文件,但为什么数据要用文件来储存呢?为什么要使用文件呢?且待我细细道来。


一、为什么使用文件

我们知道,我们写的程序什么的数据什么的都存在文件中,倘若没有存在文件中,那么它们就存在了电脑的内存中,而且如果程序退出的话,内存就会进行回收,我们的数据就也回收了,也就丢失了,等到程序再次运行,是看不见上次程序的数据的,如果将数据进行持久化的保存,我们就可以使用文件。

二、什么是文件

2.1文件的概念

磁盘(硬盘)上的文件是文件。文件是计算机中的一种数据存储形式,用来存储和组织数据的集合。文件可以包含文本、图像、音频、视频等各种形式的数据。在计算机系统中,文件通常以扩展名作为标识,不同的扩展名代表不同的文件类型。文件可以存储在计算机的硬盘、固态硬盘、光盘等各种存储介质上,并可以通过操作系统提供的文件系统进行读取、写入、复制、移动等操作。

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

2.2程序文件

程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。例如下面:

2.3数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

我们以前会把所处理的数据输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上吧数据读取到内存中使用,这里处理的就是磁盘上的文件。

2.4文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。文件名包含3个部分:文件路径+文件名主干+文件后缀

例如:D:\仓库code\lianxi.c

为了方便起见,文件标识常被称为文件名。

2.5二进制文件和文本文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。数据在内存中以二进制的形式存储,如果不加转换的输出到外存的文件中,就是二进制文件 。如果要求在外存上以ASCLL码的形式存储,则需要在存储前转换。以ASCLL字符的形式存储的文件就是文本文件

字符一律以ASCLL形式存储,数值型数据既可以使用ASCLL形式存储,也可以使用二进制形式存储。如果有一个整数10000,以ASCLL码形式输出到磁盘,则磁盘中占用5 个字节(每一个字符一个字节),而二进制形式输出的的话,则在磁盘上只会占4个字节。

三、文件操作

3.1文件指针

缓冲文件系统中,主要的就是"文件类型指针",也就是"文件指针"。每一个文件在内存中都会开辟一个文件信息区,用来存放文件的相关信息(如文件的名字,文件状态以及文件当前的位置等等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名为FILE。

不同的编译器不同环境stdio.h头文件中的文件类型申明是不一样的:

我们可以看到VS2022中对于FILE的申明定义。下面是VS2013中对FILE的申明定义:

struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;

可以看到FILE其实就是一个包含各种成员的结构体,我们不需要这些成员都是什么,我们只需要会使用FILE就可以。

我们一般都是用一个FILE的指针来维护这个FILE结构的变量,这样比较方便。

我们可以创建一个FILE* 的指针变量:

FILE* pf;

这里就使用FILE创建了一个pf的指针,也就是文件指针变量。定义pf就是一个指向FILE类型数据的指针变量,可以使用pf,指向某一个文件的文件信息区,通过文件信息区中的信息就可以访问数据,也就是说通过文件指针变量就可以间接的找到与它关联的文件。

3.2文件的打开与关闭

文件在读取之前应该打开文件,读取完了之后应该关闭文件。文件打开的时候,会返回一个FILE*的指针变量指向该文件,也相当于建立的文件和指针的关系。

C语言中规定使用fopen函数来打开文件,fclose来关闭文件。

FILE * fopen ( const char * filename, const char * mode );

fopen里面第一个参数是文件名也就是文件的地址,地址可以用绝对地址或者是相对地址。第二个参数是以什么方式访问文件。

这里可以通过以下的方式访问:

read:打开文件进行输入操作。该文件必须存在。write:为输出操作创建一个空文件。如果同名的文件已经存在,则其内容将被丢弃,并将该文件视为新的空文件。"a"append:打开文件以便在文件末尾输出。输出操作总是在文件末尾写入数据,展开它。重定位操作(fseek, fsetpos, rewind)将被忽略。如果文件不存在,则创建该文件。"r+"read/update:打开一个文件进行更新(包括输入和输出)。该文件必须存在。"w+"write/update:创建一个空文件并打开它进行更新(输入和输出)。如果同名文件已经存在,其内容将被丢弃,并将该文件视为新的空文件。"a+"append/update:打开一个文件进行更新(包括输入和输出),所有输出操作都在文件末尾写入数据。重定位操作(fseek、fsetpos、rewind)会影响下一个输入操作,但输出操作会将位置移回文件末尾。如果文件不存在,则创建该文件。

|--------|----|-----------|
| ⽂件使⽤⽅式 | 含义 | 如果指定⽂件不存在 |

|-----------|----------------------|----------|
| "r"(只读) | 为了输⼊数据,打开⼀个已经存在的⽂本⽂件 | 出错 |
| "w"(只写) | 为了输出数据,打开⼀个⽂本⽂件 | 建⽴⼀个新的⽂件 |
| "a"(追加) | 向⽂本⽂件尾添加数据 | 建⽴⼀个新的⽂件 |
| "rb"(只读) | 为了输⼊数据,打开⼀个⼆进制⽂件 | 出错 |
| "wb"(只写) | 为了输出数据,打开⼀个⼆进制⽂件 | 建⽴⼀个新的⽂件 |
| "ab"(追加) | 向⼀个⼆进制⽂件尾添加数据 | 建⽴⼀个新的⽂件 |
| "r+"(读写) | 为了读和写,打开⼀个⽂本⽂件 | 出错 |
| "w+"(读写) | 为了读和写,建议⼀个新的⽂件 | 建⽴⼀个新的⽂件 |
| "a+"(读写) | 打开⼀个⽂件,在⽂件尾进⾏读写 | 建⽴⼀个新的⽂件 |
| "rb+"(读写) | 为了读和写打开⼀个⼆进制⽂件 | 出错 |
| "wb+"(读写) | 为了读和写,新建⼀个新的⼆进制⽂件 | 建⽴⼀个新的⽂件 |
| "ab+"(读写) | 打开⼀个⼆进制⽂件,在⽂件尾进⾏读和写 | 建⽴⼀个新的⽂件 |

int fclose ( FILE * stream );

fclose就是把之前用来接收的指针传进去,就关闭了。

If the stream is successfully closed, a zero value is returned.

On failure, EOF is returned.

我们可以看到,如果关闭成功最后返回的就是0,如果关闭失败那么返回的就是EOF。

这样我们就可以通过代码来简单的演示一下:

我们可以首先在D盘project目录下创建一个text.tst文件,之后同过代码来访问:

#include<stdio.h>
int main()
{
	FILE* df = fopen("D:\\project\\text.txt","r");
	if (df == NULL)
	{
		perror("FILE::");
		return 1;
	}
	else
	{
		printf("访问成功!\n");
	}
	
	int i=fclose(df);
	if (i == 0)
	{
		df = NULL;
		return 0;
	}
	else
		perror("fclose::");
	return 0;
}

这里就是通过read的方式访问这个text,当然是访问到了,所以最后会打印访问成功,而且也关闭成功。

我们如果把那个text删除,看看运行结果如何:

这时候就会说FILE打开文件这块没有这个文件或者目录。

基于fopen和fclose就可以实现文件的打开和关闭。如果方式变为"w",那么会把之前里面的数据进行清除,把上一次的信息都销毁掉。

四、文件的顺序读写

|---------|---------|-------|
| 函数名 | 功能 | 适⽤于 |
| fgetc | 字符输⼊函数 | 所有输⼊流 |
| fputc | 字符输出函数 | 所有输出流 |
| fgets | ⽂本⾏输⼊函数 | 所有输⼊流 |
| fputs | ⽂本⾏输出函数 | 所有输出流 |
| fscanf | 格式化输⼊函数 | 所有输⼊流 |
| fprintf | 格式化输出函数 | 所有输出流 |
| fread | ⼆进制输⼊ | ⽂件输⼊流 |
| fwrite | ⼆进制输出 | ⽂件输出流 |

当我们可以打开关闭文件了,就可以实现对文件里面顺序读写。

4.1fgetc

int fgetc ( FILE * stream );

这是读取获得单个字符

返回值:

成功后,将返回字符 read(提升为 int 值)。

返回类型为 int 以容纳特殊值 EOF,该值指示失败:

如果位置指示符位于文件末尾 ,则函数返回 EOF 并设置 streameof 指示符feof)。

如果发生其他读取错误,该函数还会返回 EOF,但会设置其错误指示符ferror)。

我们把之前的文件还原,在text.txt文件里写入abcdef,这里用fgetc函数来获取字符:

int main()
{
	//打开文件
	FILE* df = fopen("D:\\project\\text.txt","r");
	if (df == NULL)
	{
		perror("FILE::");
		return 1;
	}
	else
	{
		printf("访问成功!\n");
	}
	//读取
	int j = 0;
	j = fgetc(df);
	printf("%c", j);
	j = fgetc(df);
	printf("%c", j);
	j = fgetc(df);
	printf("%c", j);

	//关闭文件
	int i=fclose(df);
	if (i == 0)
	{
		df = NULL;
		return 0;
	}
	else
		perror("fclose::");
	return 0;
}

运行结果:

这样就获取字符成功了。

4.2fputc

int fputc ( int character, FILE * stream );

这里第一个参数是要写的字符 ,第二个参数是要写入的目标文件

返回值:

On success, the character written is returned.

If a writing error occurs, EOF is returned and the error indicator (ferror) is set.

​​如果成功,则返回所写的字符。

如果发生写错误,则返回EOF并设置错误指示器(error)。

我们也可以用代码来写一下,把访问方式改成"w",可以覆盖掉之前的数据:

//打开文件
FILE* df = fopen("D:\\project\\text.txt","w");

//输入字符
char j = 'a';
for (j = 'a'; j <= 'z'; j++)
{
	fputc(j, df);
}

这里用一个循环实现输入a到z,我们打开txt可以看到成功了:

4.3fputs

int fputs ( const char * str, FILE * stream );

fputs函数是输入一个字符串,可以把字符串输入到文件中。第一个参数是要输入的字符串,第二个参数是目标文件。

我们就直接上代码:

//打开文件
FILE* df = fopen("D:\\project\\text.txt","w");

fputs("hello world\n", df);

我们往之前的文件中写入hello world。运行程序后:

发现之前的被覆盖,成功的输入进去了新的字符串。

4.4fgets

char * fgets ( char * str, int num, FILE * stream );

fgets是读取获得一个字符串,第一个参数是要把读取到的字符串存到的字符数组,第二个是要读取的个数,第三个是目标文件。

我们也直接代码演示:

//打开文件
FILE* df = fopen("D:\\project\\text.txt","r");

//输出字符串
char arr[20];
fgets(arr, 5, df);
printf("%s", arr);

这里就是读取5个字符存到arr数组中,并且打印出来:

这里为什么只有四个字母,因为它还要加上一个\0,也算一个,所以是五个。


总结

今天先到这里,,剩下的下一篇再继续写。

相关推荐
a00234500113 分钟前
python类型转换&深浅拷贝
开发语言·python
2301_7665360542 分钟前
调试无痛入手
开发语言·前端
rjszcb1 小时前
JSON格式,C语言自己实现,以及直接调用库函数(一)
c语言·json
+7201 小时前
Java 的 HttpClient 中使用 POST 请求传递参数
java·开发语言
@大迁世界2 小时前
构建 Next.js 应用时的安全保障与风险防范措施
开发语言·前端·javascript·安全·ecmascript
水瓶丫头站住3 小时前
Qt中QRadioButton的样式设置
开发语言·qt
xinghuitunan4 小时前
时间转换(acwing)c/c++/java/python
java·c语言·c++·python