首页 >> 大全

【c语言进阶】文件操作(上)

2023-12-23 大全 21 作者:考证青年

文章目录 二、文件的打开和关闭: 三、文件的顺序读写: 2.文本行的读与写 fgets 与 fputs 3.格式化输出函数 和: 4.二进制的输入与输出fwead和: 5.流的概念:6.辨析输入与输出:7.辨析三组函数: 总结:

前言:

在前面的通讯录学习中,我们发现,当程序结束以后,内存空间就会被释放并回收,我们所存的通讯录人的消息就全部消失了。如此,我们无法将数据真正保留下来。

所以,我们的目的便是希望将数据保留在本地,只有当我们进行删除操作时,才将对应的数据删除掉,即尝试实现数据的持久化。而我们实现数据持久化的方式一般有两种:使用 数据库 或将数据以 文件操作 存放至硬盘中。今天我们就来学习一下文件操作相关知识。

一、文件概述: 1.什么是文件:

我们通常所说的文件,一般是指存放在我们计算机本地硬盘上的文件。但是在我们的程序设计中,则指的是 程序文件 与 数据文件 两种文件(根据文件功能分类)。

1.1.程序文件:

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

1.2数据文件:

本章讨论的是数据文件。

在以前各章所处理数据的输入输出都是以终端为对象的,即从终端加粗样式的键盘输入数据,运行结果显示到显示器上。而今天我们的目的则是将数据信息输入至我们的本地磁盘上,而当我们想要对数据进行操作时,再从本地硬盘进行读取。

1.3文件名: 1.3.1绝对路径:

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

例如: c:\code\test.txt

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

1.3.2相对路径:

如果打开所在文件路径的文件,则不用前面的文件路径

例如: test.txt

如果要打开所在文件的上一层文件,则在前面+一个 . ./ ;

例如: . ./test.txt

同理,如果是上上一层文件,则+ . ./. ./

二、文件的打开和关闭:

我们在使用或操作我们的文件之前,首先需要在我们的程序中及将其打开,于是我们就来研究一下文件的打开和关闭方式。

1.文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

每个文件在被使用时,都会在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.

例如,编译环境提供的 stdio.h 头文件中有以下的文件类型申明

此时结构体内的指针指向保存文件信息的成员。

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息 ,使用者不必关心细节。

一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

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

FILE* p;
//定义一个文件指针p

像这样,我们就能创建出一个文件指针,而接下来就可以使这个文件指针 p 指向某个文件信息区(FILE 类型的结构体变量),并通过该文件信息区中所保存的信息来访问本地硬盘内的文件了。这样,我们通过使用文件指针就可以找到与其相关联的文件了。

2.文件的打开与关闭:

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。

在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

ANSIC 规定使用fopen函数来打开文件,来关闭文件.

fopen 函数的使用方式:

FILE* p = fopen(const char* filename, const char* mod);

函数的使用方式为:

fopen(FILE* strname);

int main()
{//D:\\code\\test.txt - 绝对路径//FILE* pf = fopen("test2.txt", "w");if (pf == NULL){perror("fopen");return 1;}else{printf("打开文件成功\n");}//读文件//....//关闭文件fclose(pf);pf = NULL;return 0;
}

3.文件的打开方式: 文件使用方式含义如果指定文件不存在

“r”(只读)

为了输入数据,打开一个已经存在的文本文件

出错

“w”(只写)

为了输出数据,打开一个文本文件(会清除文件里的消息)

建立一个新的文件

“a”(追加)

向文本文件尾添加数据

建立一个新的文件

“rb”(只读)

为了输入数据,打开一个二进制文件

出错

“wb”(只写)

为了输出数据,打开一个二进制文件

建立一个新的文件

“ab”(追加)

向一个二进制文件尾添加数据

出错

“r+”(读写)

为了读和写,打开一个文本文件

出错

“w+”(读写)

为了读和写,建议一个新的文件

建立一个新的文件

“a+”(读写)

打开一个文件,在文件尾进行读写

建立一个新的文件

“rb+”(读写)

为了读和写打开一个二进制文件

出错

“wb+”(读写)

为了读和写,新建一个新的二进制文件

建立一个新的文件

“ab+”(读写)

打开一个二进制文件,在文件尾进行读和写

建立一个新的文件

三、文件的顺序读写: 功能函数名适用于

字符输入函数

fgetc

所有输入流

字符输出函数

fputc

所有输出流

文本行输入函数

fgets

所有输入流

文本行输出函数

fputs

所有输出流

格式化输入函数

所有输入流

格式化输出函数

所有输出流

二进制输入

fread

文件

二进制输出

文件

1.字符的读与写 fgetc 与 fputc: 字符的读取函数 fputc :

int main()
{FILE* pf = fopen("test.txt", "w");if (NULL == pf){perror("fopen");return 1;}//写文件/*fputc('a', pf);fputc('b', pf);fputc('c', pf);fputc('d', pf);*/char ch = 0;for (ch = 'a'; ch <= 'z'; ch++){fputc(ch, pf);}//关闭文件fclose(pf);pf = NULL;return 0;
}

运行结果:

这就是字符的写入,大家会在该项目找到这个文件。

字符的读取函数 fgetc :

我们在上面代码的基础下展示文件的读取。

int main()
{FILE* pf = fopen("test.txt", "r");if (NULL == pf){perror("fopen");return 1;}//读文件int ch = fgetc(pf);printf("%c\n", ch);ch = fgetc(pf);printf("%c\n", ch);ch = fgetc(pf);printf("%c\n", ch);//关闭文件fclose(pf);pf = NULL;return 0;
}

运行结果:

注意:

组合应用:

int main()
{FILE* pf = fopen("test.txt", "w");  //以只写的方式打开文件if (pf == NULL){perror("fopen");return 0;}char ch = 0;for (ch = 'a'; ch <= 'z'; ch++)   //向文件写入26个小写英文字母{fputc(ch, pf);}fclose(pf);pf = NULL;pf= fopen("test.txt", "r");  //以只读的方式打开文件if (pf== NULL){perror("fopen");return 0;}while (ch != EOF)   //判断是否读取到文件末尾{ch = fgetc(pf);   //从文件中读取字符printf("%c", ch);   //打印读取字符}fclose(pf);pf = NULL;return 0;
}

代码结果:

2.文本行的读与写 fgets 与 fputs fputs读取字符串:

int main()
{FILE* pf = fopen("test.txt", "w");if (NULL == pf){perror("fopen");return 1;}//写文件//测试写一行数据fputs("hello world\n", pf);fputs("hello bit\n", pf);return 0;
}

运行结果:

fgets读取字符串:

特殊情况:

int main()
{FILE* pf = fopen("test.txt", "r");if (NULL == pf){perror("fopen");return 1;}//读文件//测试一行数据char buf[20] = {0};fgets(buf, 20, pf);printf("%s", buf);fgets(buf, 20, pf);printf("%s", buf);//关闭文件fclose(pf);pf = NULL;return 0;
}

代码结果:

3.格式化输出函数 和: 的格式化写入:

其实该函数和函数一模一样,只是前面多了一个指向文件的指针! 这里的意思其实是将后面的数据以不同的格式写入指针指向的文件信息中。

struct S
{char name[20];int age;float score;
};int main()
{struct S s = { "zhangsan", 20, 95.5 };FILE* pf = fopen("test.txt", "w");if (NULL == pf){perror("fopen");return 1;}//格式化的写入文件fprintf(pf, "%s %d %f\n", s.name, s.age, s.score);//关闭文件fclose(pf);pf = NULL;return 0;
}

运行结果:

的格式化读取:

一样的,都是多了一个文件指针而已,其他都是一模一样的!这里的意思是将文件指向的文件消息以不同格式读出并且保存在不同类型的变量中。

int main()
{struct S s = { 0 };FILE* pf = fopen("test.txt", "r");if (NULL == pf){perror("fopen");return 1;}//格式化的读取文件fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));//打印看数据printf("%s %d %f\n", s.name, s.age, s.score);//关闭文件fclose(pf);pf = NULL;return 0;
}

运行结果:

4.二进制的输入与输出fwead和: 二进制的输出:

int main()
{struct S s = { "张三", 20, 98.5};FILE* pf = fopen("test.txt", "wb");if (NULL == pf){perror("fopen");return 1;}//写文件fwrite(&s, sizeof(struct S), 1, pf);//关闭文件fclose(pf);pf = NULL;return 0;
}

文本形式是这样的:

但是我们转出2进制看就是这样的:

二进制的输入fread:

int main()
{struct S s = { 0};FILE* pf = fopen("test.txt", "rb");if (NULL == pf){perror("fopen");return 1;}//读文件fread(&s, sizeof(struct S), 1, pf);printf("%s %d %f\n", s.name, s.age, s.score);//关闭文件fclose(pf);pf = NULL;return 0;
}

代码结果:

5.流的概念:

小伙伴对于上面所提到的输入流输出流肯定非常迷惑。可以看到流其实流是一个极其抽象的概念,我们可以把它理解成C程序与外部设备进行交流的一个媒介,文件是一个流,我们的键盘,屏幕也是一个流,并且他们有各自专门的文件指针的名称。

其实我们也可以用上面的,来实现和scanf

struct S
{char name[20];int age;float score;
};int main()
{struct S s = { 0 };fscanf(stdin, "%s %d %f", s.name, &(s.age), &(s.score));fprintf(stdout, "%s %d %f\n", s.name, s.age, s.score);//int ch = fgetc(stdin);//fputc(ch, stdout);return 0;
}

6.辨析输入与输出:

在这里,为了方便辨析是输入还是输出。我们可以把自己当作内存!以内存为主体来判断是输出还是输入。比如键盘上打字对于内存来说是输入/读取,在屏幕上打印是输出/写入。写文件是将内存的东西放入文件是输出/写入,从文件获取信息是输入/读取。

7.辨析三组函数: 7.1.scanf和: 7.2.和: 7.3.和

相信大家看到前面的s就知道肯定是和字符串有关,其实这两个函数就是将格式化数据和字符串数据相互转化罢了,看一个栗子就够了!

int main()
{struct S s = {"zhangsan", 20, 98.5};char buf[100] = { 0 };//转化成字符串形式sprintf(buf, "%s %d %f", s.name, s.age, s.score);//按照字符串打印的printf("%s\n", buf);struct S tmp = { 0 };//转化为格式化数据sscanf(buf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));//打印结构体数据printf("%s %d %f\n", tmp.name, tmp.age, tmp.score);return 0;
}

总结:

今天介绍了文件的一些基本知识,对于随机读取,缓冲区的相关知识我将会在下一篇文章讲解!

更新不易,辛苦各位小伙伴们动动小手,三连走一走 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了