1. 什么是文件:
文件是计算机中存储数据的一种方式,它可以包含文本、图像、音频、视频等各种形式的信息。在计算机系统中,文件被组织成一个个独立的单元,可以通过文件名来标识和访问。文件可以存储在计算机的硬盘、固态硬盘、光盘、U盘等存储介质上,文件通常由两部分组成:文件名和文件内容。文件名是用来标识文件的唯一名称,可以根据需要进行命名。文件内容是实际存储在文件中的数据,可以是文本、二进制数据或其他格式的数据,文件在计算机系统中起到了重要的作用,它们可以用于存储和传输数据,作为程序的输入和输出,以及用于组织和管理数据。通过文件系统,用户可以创建、打开、读取、写入、修改和删除文件。
1.1. windows中文件的类型:
前边我们聊到不同后缀代表着不同的文件类型,下边我们来了解一下常见的文件类型:
- text.txt 后缀为.txt的为文本文件
- text.exe 后缀为.exe的为可执行文件
- text.jpg 后缀为.jpg的为图片文件
- text.mp3 后缀为.mp3的为音频文件
- text.mp4 后缀为.mp4的为视频文件
上图中仅为部分文件类型,如有兴趣的小伙伴可以去深入了解喔
1.2. c程序中的文件:
一个c程序要想变成最终可以执行的文件,会经历编译-->链接-->运行三个步骤,而这三个步骤又分别对应着三个不同的文件.c文件编译以后先生成.o(.obj)文件,链接生成.exe的可执行文件,最终再执行
1.3. 二进制文件及文本文件:
二进制文件:数据在内存当中是以二进制的格式存储的,如果不加以转换直接输出到外存文件当中的称为二进制文件
文本文件:存入文件前加以转换为1ASCII格式存储在文件中的文件为文本文件
举例:假设有一个数字5000,那么它以二进制或文本的形式在内存当中分别是如何存储的呢
(注:相应的ASCII码值对应着不同的十进制数,字符5的ASCII码值为00110101 0为00110000)
2. 文件流:
文件流是一种用于读取和写入文件的数据流。它提供了一种方便的方式来处理文件的输入和输出操作,我们常使用的printf函数和scanf函数所对应使用的就是标准输入和输出流,只不过这些流在我们打开编译器时已经默认开启了,所以对应程序员来说直接使用即可
c程序默认打开的流:
C语言提供了标准库函数来支持文件流操作,主要包括以下几个步骤:
-
打开文件:使用
fopen
函数打开一个文件,并返回一个指向该文件的指针。需要指定文件名和打开模式(如读取、写入、追加等) -
读取文件:使用
fscanf
或fgets
等函数从文件中读取数据。fscanf
可以按照指定的格式从文件中读取数据,而fgets
则逐行读取字符串 -
写入文件:使用
fprintf
或fputs
等函数将数据写入文件。fprintf
可以按照指定的格式将数据写入文件,而fputs
则将字符串写入文件 -
关闭文件:使用
fclose
函数关闭已打开的文件。关闭文件后,将释放相关的资源
C语言文件流的使用需要注意以下几点:
- 在打开文件时,需要确保文件存在或者具有相应的权限
- 在读取或写入文件时,需要确保文件指针指向正确的位置
- 操作完成后,需要及时关闭文件,以释放资源
3. 文件指针的创建:
文件指针的创建与前文中的指针创建大同小异,FILE* 变量名
int main()
{FILE* pf; //文件的创建return 0;
}
举例:
4. 文件的打开与关闭:
4.1. fopen与fclose函数:
fopen函数:打开文件
FILE * fopen ( const char * filename, const char * mode );
filename:要打开的文件
mode:以什么样的方式打开文件
(如果文件被成功打开,返回一个指向file对象的指针,否则返回NULL)
fclose函数:关闭文件
int fclose ( FILE * stream );
stream:指向file文件的指针,该对象为要关闭的流
(如果文件被成功关闭,返回0,关闭失败,返回EOF)
file打开时mode参数:
举例:
int main()
{FILE* pf; //文件的创建pf = fopen("a1.txt", "wb");if (pf != NULL) //判断文件是否打开成功{int i = 0;while (i < 11){fputc(i, pf); //fputc写入一个字符i++;}fclose(pf); //关闭文件}return 0;
}
5. 文件的顺序读写:
5.1. 顺序读写函数:
5.2. fgets函数:
从文件中获取一个字符
int fgetc ( FILE * stream );
(如果读取成功,返回读取的字符,整形提升至int型,读取失败返回EOF)
举例:
int main()
{FILE* p;p = fopen("test1.txt", "r");if (p != NULL){int a = fgetc(p);printf("%d", a);fclose(p);}return 0;
}//执行结果
97 所以该字符是a,a的ASCII值为97
5.3. fputc函数:
写入一个字符到文件中:
int fputc ( int character, FILE * stream );
character:写入的字符
(如果写入成功,则字符被写入到文件当中,失败返回EOF)
举例:
int main()
{FILE* p1;p1 = fopen("test1.txt", "w");if (p1 != NULL){fputs("a", p1);fclose(p1);}return 0;
}//执行结果
此时test1.txt文件当中写入了字符a
5.4. fgets函数:
从文件当中获取字符串
char * fgets ( char * str, int num, FILE * stream );
(如果读取成功,返回str,如果读取到文件末尾,则设置eof指示符(feof),读取失败返回NULL)
举例:
int main()
{FILE* p2;char a[100];p2 = fopen("test1.txt", "r");if (p2 != NULL){if (fgets(a, 20, p2) != NULL){printf("%s", a);}fclose(p2);}return 0;
}
5.5. fputs函数:
将字符串写入到文件中
int fputs ( const char * str, FILE * stream );
(如果成功返回一个>0的数,失败函数返回EOF并设置错误指示器)
举例:
int main()
{FILE* p3;char a[] = "qwerty";p3 = fopen("test1.txt", "w");if (p3 != NULL){int a1 = fputs(a, p3);if (a1 >= 0)fclose(p3);elseperror("fputs:");}return 0;
}
5.6. fscanf函数和fprintf函数:
5.6.1. scanf函数以及printf函数:
在讲fscanf以及fprintf这两个函数前,我们先来了解一下scanf和printf函数又是如何使用的呢
语法:
int printf ( const char * format, ... ); //格式化输入函数
int scanf ( const char * format, ... ); //格式化输出函数
下边我们来看看它们是如何使用的:
//从键盘上输入一个数,输出到控制台中
int main()
{int a = 0;scanf("%d", &a);printf("a的值为:%d", a);return 0;
}
该两个函数为格式化输入输出函数,所以在使用这两个函数时必须带有格式,那么它们又和fscanf和fprintf有什么区别呢,下边我们一起来了解一下
5.6.2. fscanf,fprintf,scanf及printf四个函数的区别:
语法:
int fscanf ( FILE * stream, const char * format, ... );
int fprintf ( FILE * stream, const char * format, ... );
(如果成功,返回函数成功填充的项数,而匹配失败或者到达文件末尾返回值小于或等于0,在任何数据都未被读取到之前发生错误,fnahuiEOF)
差异对比:
fscanf的使用:
int main()
{FILE* p4;p4 = fopen("test1.txt", "r+"); //以读的方式打开int s = 1000;char a2[10] = { 0 };if (p4 != NULL){int a3 = fscanf(p4, "%d%s", &s,a2); //读取两个数放入相对应的变量当中if (a3 != EOF){printf("%d\n", s);printf("%s\n", a2);fclose(p4);}else{perror("fscanf");}}return 0;
}
fprintf的使用:
int main()
{FILE* p4;p4 = fopen("test1.txt", "w+");int s = 1000;char a2[10] = "abcdef";if (p4 != NULL){int a3 = fprintf(p4, "%d%s", s, a2);if (a3 != EOF){fclose(p4);}else{perror("fprintf");}}return 0;
}
如何使用fscanf或fprintf将数据输入输出到控制台当中:
(这里就要使用到我们之前所讲的输入输出流了)
举例:
int main()
{int a = 0;printf("请输入一个数:");int q = fscanf(stdin, "%d", &a); //stdin标准输入流if (q == EOF){perror("fscanf");}fprintf(stdout, "a此时的值为:%d", a); //stdout标准输出流return 0;
}//执行结果
请输入一个数:123
a此时的值为:123
同理前边适用于所以流的函数都可以如此使用
5.7. fread函数:
以二进制的方式在文件中读取数据
语法:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
(如果读取成功,返回读取的个数,如果size和count为0,则函数返回0,函数内容不发生改变)
ptr:指向大小至少为(size_t count)字节的内存块的指针,转换为void*类型
size:要读取的每个元素大小,单位是字节
count:读取的个数
stream:文件指针
举例:
#include <stdlib.h>
int main()
{FILE* p5;int count = 5;char* pf = (char*)malloc(sizeof(char) * count);if (pf == NULL){perror("malloc");return 1;}p5 = fopen("test1.txt", "rb"); //以二进制的方式读取数据if (p5 != NULL){int q = fread(pf, sizeof(char), count, p5);for (int i = 0; i < count; i++){printf("%c ", *(pf + i));}fclose(p5);}else{perror("fopen");}free(pf);pf = NULL;
}//执行结果
a b c d e
如有对动态内存malloc这些不理解的小伙伴可以去看看动态内存管理这篇文章哟
5.8. fwrite函数:
语法:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
(与fread函数大同小异,这里博主就不做结束咯)
举例:
#include <stdlib.h>
int main()
{FILE* p6;int count = 5;char a5[] = "sdfgh";p6 = fopen("test1.txt", "wb"); //以二进制的方式读取数据if (p6 != NULL){int q = fwrite(a5, sizeof(char), count, p6);fclose(p6);}else{perror("fopen");}
}//执行结果
此时成功向test1.txt文件当中添加数组a5中的字符串
6. 文件的随机读取:
6.1 fseek函数:
int fseek ( FILE * stream, long int offset, int origin );
stream:文件指针
offset:二进制文件:要从原点偏移的字节数
文本文件:要么为0,要么有ftell返回一个值
origin:表示偏移量的开始位置
SEEK_SET:文件的起始位置
SEEK_CUR:文件指针当前结束的位置
SEEK_END:文件的结束位置
(如果成功返回0,否则,返回非零值)
举例:
int main()
{FILE* pFile;pFile = fopen("test1.txt", "wb");fputs("I'm is a handsome guy", pFile); //向文件中写入一组字符fseek(pFile, 7, SEEK_SET); //光标从5的位置开始执行操作fputs("no ", pFile); fclose(pFile);return 0;
}//执行结果
I'm is no andsome guy
6.2 ftell函数:
语法:
long int ftell ( FILE * stream );
(如果成功,返回位置指示器当前的值,失败,返回-IL)
举例:
(相较于之前的代码,咱来举例看看)
int main()
{FILE* pFile;pFile = fopen("test1.txt", "wb");fputs("I'm is a handsome guy", pFile); //向文件中写入一组字符fseek(pFile, 7, SEEK_SET); //光标从5的位置开始执行操作fputs("no ", pFile);long size = ftell(pFile); //判断文件中光标的位置printf("%ld", size);fclose(pFile);return 0;
}
6.3 rewind函数:
语法:
void rewind ( FILE * stream );
(让文件指针的位置回到起始位置)
举例:
int main()
{FILE* p7;p7 = fopen("test1.txt", "w");if (p7 != NULL){int q = fputs("abcdefgh", p7); //向文件当中写入“abcdefg”这个字符串if (q == EOF){perror("fputs");}fseek(p7, 4, SEEK_SET); //此时文件指针应指向erewind(p7); //将文件指针返回到文件起始位置FILE* p8 = fopen("test1.txt", "r");char q1 = fgetc(p8); //此时q1的值应为aprintf("%c\n", q1);fclose(p7);fclose(p8);}else{perror("fopen");}return 0;
}//执行结果
a
7. 文件读取结束的判定:
7.1 错误使用的feof函数:
语法:
int feof ( FILE * stream );
(如果设置l与流相关的文件结束指示符,则返回一个非零值,否则返回零)
- ⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
- ⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数
int main()
{FILE* p9;int q = 0; //记录文件读取的个数p9 = fopen("test1.txt", "r");if (p9 != NULL){while (fgetc(p9) != EOF){q++;}if (ferror(p9)) //文件错误时返回0printf("文件读取发生错误!\n");else if (feof(p9))printf("文件读取完毕\n");fclose(p9);}else{perror("fopen");}printf("文件中有多少个字符:%d", q);return 0;
}//执行结果
文件读取完毕
文件中有多少个字符:8
8. ⽂件缓冲区:
ANSIC 标准采⽤“缓冲⽂件系统” 处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为 程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓 冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输 ⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等),缓 冲区的⼤⼩根据C编译系统决定的
下边小博给兄弟们找个一个题解方便大家进一步了解:
(今日分享到此结束,如觉得有帮助还请点赞三联支持一波呢,Thanks♪(・ω・)ノ)