这些信息是保存在一个结构体变量中 。该结构体类型是由系统声明的,取名为FILE 。
每当打开一个文件时,系统就会根据文件情况自动创建一个FILE结构的变量,并填充其中的信息 。
struct _iobuf {char *_ptr;int_cnt;char *_base;int_flag;int_file;int_charbuf;int_bufsiz;char *_tmpfname;};typedef struct _iobuf FILE;
所以我们一般通过文件指针变量找到与它相关联的文件
FILE* pf;//文件指针变量
流程:
我们在程序中实现文件打开和关闭 , 一般按照三步骤:
打开文件读/写文件关闭文件
我们在打开文件时,又不得不引入如下的函数:
FIEL* fopen(const char* filename, const char* mode)
其中的参数
————文件名 。
mode—————打开方式 。
以下是打开方式的各个操作符:
下面就是使用文件的三步骤例子:
#include int main (){FILE * pFile;//打开文件pFile = fopen ("myfile.txt","w");//文件操作if (pFile!=NULL){fputs ("fopen example",pFile);//关闭文件fclose (pFile);}return 0;}
文件路径:
文件路径指定到文件或文件夹的位置的描述 。它是由一系列文件夹的名称、符号和文件名组成的 。在操作系统中,文件路径可以是绝对路径或相对路径 。
相对路径:指定文件或文件夹的位置相对于当前工作目录 。例如:
在指定路径时,可以使用一些特殊符号来描述路径 。如:
文件的顺序读写:
【初识 C语言文件操作】文件的顺序读写是指按照文件中数据的顺序依次读取或写入数据 。在进行文件读写时 , 操作系统会维护一个文件指针 , 用于指示当前读写的位置 。初始时 , 文件指针指向文件的开头 。
顺序读写的过程如下:
打开文件,获取文件句柄 。
从文件句柄中读取数据,操作系统会自动将文件指针指向下一个数据的位置 。
继续读取数据,直到读取到文件末尾 。
顺序写入的过程如下:
打开文件,获取文件句柄 。
向文件句柄中写入数据 , 操作系统会自动将文件指针指向下一个数据的位置 。
继续写入数据,直到写入完所有数据 。
顺序读写可以提高文件读写的效率,因为每次读写时都能够连续地访问相邻的数据,避免了频繁地寻找数据的过程 。
接下来我们就来实现文件的读写
首先我们来认识几个函数:
实现字符输入输出: fputc:
fgetc是C语言中的标准输入输出库函数 , 用于从指定的文件指针中读取一个字符 。其原型为:
int fputc(int character, FILE *stream);
#define _CRT_SECURE_NO_WARNINGS1#include int main() {FILE* pf = fopen("test.txt", "w");if (pf == NULL) {perror("fopen");return 1;}//写文件char ch = 0;for (ch = 'a'; ch <= 'Z'; ch++){fputc(ch, pf);}fclose(pf);pf = NULL;return 0;}
上述代码会读取名为"test.txt"的文件中的所有内容,并将26个英文字母存放在文件“test.txt”中 。
此时我们到当前程序的目录底下就会发现:
此时该文件就存放了a——z这26个字母 。
fgetc:
fgetc是C语言中的标准输入输出库函数,用于从指定的文件指针中读取一个字符 。其原型为:
int fgetc(FILE *stream);
其中,为指向文件的指针 。函数返回值为读取的字符的ASCII码值,如果已经到达文件末尾,则返回EOF 。
使用fgetc可以逐个字符地读取文件 , 例如:
#include int main() {FILE *fp;int c;fp = fopen("test.txt", "r");if (fp == NULL) {printf("Failed to open the file.\n");return 1;}while ((c = fgetc(fp)) != EOF) {putchar(c);}fclose(fp);return 0;}
上述代码会读取名为"test.txt"的文件中的所有内容,并输出到标准输出 。
在这两个函数中,我们多次提到“流”这个概念,接下来我们就来介绍介绍“流” 。
“流”
“流”是一个高度抽象的概念!目前我们可以理解为“中转站” 。
流()通常是指某个持续的、连续的、有序的数据序列,可以是数据源(例如文件、网络连接等)中的数据流,也可以是程序中的内存流(例如输入输出流、网络流等) 。流的概念主要用于表示处理数据的可迭代性 , 它使得程序能够在处理数据的同时 , 将数据逐个读取或写入,而不需要一次性读取或写入整个数据集,从而大大提高了程序的效率和可扩展性 。流可以分为输入流和输出流,输入流用于从数据源读取数据,输出流用于向目标输出数据 。流也可以通过缓存机制来提高读写性能,即先将数据先读取到缓存中 , 再从缓存中进行读写操作 。
我们对于刚刚讲的函数中,我们可以总结出如图:
我们也可以利用我们学过的知识来解释:
只要C语言程序运行起来,就默认打开了3个流:
1.标准输入流——stdin
2.标准输出流——
3.标准错误流——
实现文本行输入输出: fputs:
fputs是一个C标准库函数 , 用于将字符串写入文件中 。它的原型为:
int fputs(const char *str, FILE *stream);
其中 , str是待写入的字符串,是目标文件指针 。
![初识 C语言文件操作](http://img.gansulong.com/231223/00391V056-0.jpg)
文章插图
函数会将字符串写入文件中,并返回一个非负整数表示操作成功 。如果出现错误 , 函数会返回EOF 。与puts函数不同的是 , fputs不会在字符串末尾加上一个换行符 。如果需要换行符,需要手动在字符串中添加一个"\n"字符 。
fgets:
fgets()是C编程语言中的一个函数,用于从文件或控制台输入中读取字符串 。它是C中标准输入/输出库(stdio.h)的一部分,通常用于从控制台中读取用户的输入 。
fgets()函数的语法是:
char *fgets(char *str, int n, FILE *stream);
str是指向存储字符串的字符数组的指针 。
n是要读取的最大字符数 。
是指向要读取的文件或stdin(标准输入)的指针 。
该函数最多从流所指向的文件中读取n-1个字符,直到遇到文件结束符(EOF)或换行符 。生成的字符串存储在str所指向的缓冲区中,并在字符串末尾添加一个空字符\0 。
fgets()在成功时返回相同的缓冲区str , 在错误时或在读取任何字符之前到达文件结束时返回NULL 。
例:
int main(){FILE* pf = fopen("test.txt", "r");char arr[100] = { 0 };fgets(arr, 100, pf);printf("%s\n", arr);fclose(pf);pf = NULL;return 0;}
运行结果如图:
若我们在文件中写:
两行数据,此时输出结果为:
这更好的说明了fgets一次只能读取一行 。
实现格式化输入输出函数: :
是C编程语言中的一个函数,用于将格式化的输出输出到文件流或控制台 。它允许程序员以特定的方式输出格式化的数据,如字符串、数字和其他变量 。该函数接受一个格式字符串作为其第一个参数 , 后跟一个参数列表 , 这些参数对应于格式字符串中的格式说明符 。格式字符串包含要打印的值的占位符,格式字符串后面的参数提供要打印的相应值 。下面是一个如何使用函数的示例:
int main() {FILE *fp;fp = fopen("test.txt", "w"); // 打开文件int num1 = 10, num2 = 20;float pi = 3.14;// 写文件fprintf(fp, "num1 = %d, num2 = %d\n", num1, num2);fprintf(fp, "pi = %f\n", pi);fclose(fp); // 关闭文件fp = NULL;return 0;}
在本例中,函数用于将格式化的输出写入文件流 。格式字符串包含变量num1、num2和pi值的占位符,它们作为函数的参数提供 。输出被写入由file指针fp指定的文件 。函数还用于将格式化的输出写入控制台 。输出类似于写入文件的输出 。最后,使用关闭文件 。
文件如图所示:
:
()是一个C库函数,用于从文件或输入流中读取数据 。它类似于标准输入函数scanf(),但它不是从标准输入读?。?而是从指定的文件流读取 。
()的语法是:
int fscanf(FILE *stream, const char *format, ...)
第一个参数是要读取的文件流,第二个参数是指定预期输入格式的字符串,其余参数是指向将接收输入值的变量的指针 。
例如,下面的代码从一个名为"test.txt"的文件中读取文件中的数值 , 并打印到屏幕上:
int main() {FILE *fp;fp = fopen("test.txt", "r"); // 打开文件//读文件fscanf(fp, "num1 = %d, num2 = %d\n", &num1, &num2);fscanf(fp, "pi = %f\n", &pi);printf("num1 = %d, num2 = %d\n", num1, num2);printf("pi = %f\n", pi);fclose(fp); // 关闭文件fp = NULL;return 0;}
请注意,与scanf()一样,()返回成功匹配和分配的输入项数 , 可用于错误检查 。
二进制的输入输出: :
是C编程语言中的一个函数,用于将数据块写入文件 。它有四个参数:指向要写入的数据的指针、要写入的每个元素的大小、要写入的元素的数量,以及指向要写入的文件的指针 。
下面是一个使用将整数写入文件的示例:
#include int main() {int num = 42;//打开文件FILE *file = fopen("file.bin", "wb");//写文件fwrite(&num, sizeof(int), 1, file);//关闭文件fclose(file);file = NULL;return 0;}
在本例中,整数num被写入名为file.bin的二进制文件中 。调用函数时带有一个指向num的指针、一个整数的大小((int))、要写入的整数的数量(在本例中为1)和一个指向文件的指针 。最后,使用关闭文件 。
此时文件中的数据为:
fread:
fread是一个C库函数,用于将二进制数据从文件读入缓冲区 。它接受四个参数:
指向将存储数据的缓冲区的指针 。
要读取的一个元素的大小 。
要读取的元素数目 。
要读取的文件的文件指针 。
函数返回从文件中成功读取的元素总数 。
例:
int main() {int num = 42;int arr[10] = { 0 };//打开文件FILE *file = fopen("file.txt", "rb");//写文件//fwrite(&num, sizeof(int), 1, file);//读文件fread(arr, sizeof(int), 1, file);printf("%d\n", arr[0]);//关闭文件fclose(file);file = NULL;return 0;}
输出结果为:
文件的随机读写: fseek:根据文件指针的位置和偏移量来定位文件指针
fseek函数是C标准库中的一个函数,用于设置文件指针的位置 。其函数原型为:
int fseek(FILE *stream, long offset, int whence);
其中,是指向文件的指针,是偏移量 , 指示偏移量相对位置,它的取值及含义如下:
fseek函数返回0表示成功,非0值表示出错 。
使用fseek函数可以对文件进行定位,从而读写文件的指定位置 。
例子:
#include int main (){FILE * pFile;pFile = fopen ( "example.txt" , "wb" );fputs ( "This is an apple." , pFile );fseek ( pFile , 9 , SEEK_SET );fputs ( " sam" , pFile );fclose ( pFile );return 0;}
文件内容为:
ftell:返回文件指针相对于起始位置的偏移量
ftell函数是一个C标准库函数,用于获取当前文件流(FILE对象)的当前文件位置指针的位置 。该函数的原型为:
long int ftell(FILE *stream);
其中,为文件流指针,表示当前要进行操作的文件流 。ftell函数的返回值为当前文件位置指针的位置,类型为long int 。
![初识 C语言文件操作](http://img.gansulong.com/231223/00391W305-1.jpg)
文章插图
ftell函数主要用于二进制文件的读写操作中 。在进行读写操作前,我们需要先打开一个文件流并设置当前文件位置指针的位置 。读写操作完成后,我们需要获取当前文件位置指针的位置,以便下次操作 。
例如:
FILE* fp = fopen("test.bin", "rb");if (fp != NULL) {fseek(fp, 0, SEEK_END);// 将文件位置指针设置到文件末尾long int file_size = ftell(fp);// 获取文件大小...fclose(fp);}
在上述代码中,我们打开了一个二进制文件test.bin,将文件位置指针设置到文件末尾,然后使用ftell函数获取了文件大小 。最后关闭了文件流 。
:让文件指针的位置回到起始位置
() 是一个标准 C 库函数,可以将文件指针指向文件的开头 。它的原型为:
void rewind(FILE *stream);
() 函数将文件位置指针指向文件开头 , 这意味着接下来的所有读取操作将从文件开始处开始 。它不会关闭文件,也不会清除错误标志或重置文件模式 。() 函数主要用于需要多次读取文件的情况,例如读取二进制文件,可以使用它来回到文件的开头位置 。
scanf/的理解
scanf是格式化的输入函数 , 针对的是标准输入流(键盘)
是格式化的输出函数,针对的是标准输出流(屏幕)
scanf和是针对标准输入/输出流的格式化输入/输出函数
/的理解
是针对所以输入流(文件流 , 输入流)的格式化输入函数
是针对所以输出流(文件流,输出流)的格式化输出函数
/的理解
是将字符串转换成格式化的数据
是将格式化的数据转化成字符串
文本文件和二进制文件
数据在内存中以二级制的形式存储 , 如果不加转换的输出到外村,就是二进制文件 。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换 。以ASCII字符的形式存储的文件就是文本文件 。
一个数据在内存中是怎么存储的呢? 字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储 。如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而 二进制形式输出,则在磁盘上只占4个字节(测试) 。
例子:
int main(){int a = 10000;FILE* pf = fopen("test.txt", "wb");fwrite(&a, 4, 1, pf);//二进制的形式写到文件中fclose(pf);pf = NULL;return 0;}
写完文件后将文件拖动到VS中
并且以二进制的方式打开:
得到结果 10 27 00 00
又因为机器是小端存储,则可以理解为:
所以才会输出:
文件的读取结束和判定 被错误使用的feof:
牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束 。而是应用于当文件读取结束的时候 , 判断是读取失败结束,还是遇到文件尾结束 。
1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ) , 或者 NULL ( fgets ) 例如: fgetc 判断是否为 EOF . fgets 判断返回值是否为 NULL .
2. 二进制文件的读取结束判断 , 判断返回值是否小于实际要读的个数 。例如: fread判断返回值是否小于实际要读的个数 。
fgetc判断是否为EOF
fgets判断返回值是否为NULL
fread要求读取count个大小为size字节的数据
如果真的读取到了count,返回count 。
如果小于则返回真是读到了的个数 。
例子:
《完成文件的拷贝》
int main(){FILE* pfread = fopen("data1.txt", "r");if (pfread == NULL){perror("fopen");return 1;}FILE* pfwrite = fopen("data2.txt", "w");if (pfwrite == NULL){perror("fopen");fclose(pfread);pfread = NULL;return 1;}int ch = 0;while ((ch = fgetc(pfread)) != EOF){fputc(ch, pfwrite);}fclose(pfread);pfread = NULL;fclose(pfwrite);pfwrite = NULL;return 0;}
我们在执行代码之前,先编写一个data1.txt的文件,里面写上abcd
此时执行代码
打开data2.txt
代码执行成功!
文件缓冲区
文件缓冲区是指在处理文件时系统为文件I/O操作所分配的一段内存空间 。当我们打开一个文件并执行读写操作时,操作系统会将文件的一部分或全部内容读入文件缓冲区中进行处理,因为读写操作比较耗时,通过文件缓冲区可以提高文件I/O操作的效率 。当我们完成读写操作后,系统将缓冲区中的数据写回到磁盘中 。因此,文件缓冲区可以有效地减少磁盘I/O操作的次数 , 从而提高系统的性能 。
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序 中每一个正在使用的文件开辟一块“文件缓冲区” 。从内存向磁盘输出数据会先送到内存中的缓冲区,装 满缓冲区后才一起送到磁盘上 。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓 冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等) 。缓冲区的大小根 据C编译系统决定的 。
正因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在程序结束时主动关闭文件 。
总结:
本文我们介绍了C语言实现文件操作,我们在此讲解了很多函数 , 希望大家在看完文章后可以动手尝试编写编写代码,自己建立再销毁一个文件 , 并对其中的内容进行修改和增加达到自定义程度 。
刚开始会对这些函数产生疑惑甚至混淆概念 。但只要每天动手尝试尝试编写函数实现文件的操作,相信很快就会上手这些函数 。
记?。白圆蝗缙鸲校 ?
speakthan words!
本章代码可以访问我的Gitee仓库:: 本仓库里的代码为c语言的测试代码 -
接下来我们会利用文件修改通讯录 。
可以再复习以下关于通讯录的创建
blog如下:
运用动态内存实现通讯录(增删查改+排序)-CSDN博客
- 文件操作学不会?快进来,带你深入理解->C语言文件操作
- 戴尔电脑如何恢复桌面文件 戴尔电脑如何恢复桌面
- C语言 枚举——称硬币
- 北碚区关于优化核酸采样的通告文件 北碚区关于优化核酸采样的通告
- 《侠客风云传》游戏界面语言繁体改简体方法
- ios手机怎么删除qq文件 ios qq删除文件
- hdf5文件怎么打开 hdf文件怎么打开
- 济宁个人所得税优惠政策文件 济宁个人所得税优惠政策
- 语言文字法律法规内容课件 语言文字法律法规内容
- 邵阳市教育局秋季开学通知 邵阳市教育局秋季开学通知文件