提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
今天来整理一下有关文件操作的知识,以达到巩固知识和温故而知新的作用。
一、文件是什么?
文件属于文件的一种,与普通文件载体不同,文件是以硬盘为载体存储在计算机上的信息集合。
文件可以是文本文档、图片、程序等等。文件通常具有点+三个字母的文件扩展名,用于指示文件类型(例如,图片文件常常以JPEG格式保存并且文件扩展名为.jpg)。
在程序设计当中,我们一般谈及的文件有两种:程序文件和数据文件。
1.程序文件
比如源文件(后缀是.c的文件),目标文件(后缀.obj的文件),可执行目标程序(后缀.exe的文件)。
2.数据文件
程序当中读写的数据,比如程序运行时读取数据的文件,或者输出内容的文件。
二、文件的打开和关闭
1.文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名
字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统
声明的,取名FILE。
以下就是文件指针的写法:
FILE*
2.fopen(打开文件的函数)
1)库中的声明:
FILE *fopen( const char *filename, const char *mode );
- filename:所要打开的文件的名字。
- mode:以什么方式来打开文件,一般有三种打开文件的方式
2)文件打开方式汇总:
3)使用举例:
int main()
{
FILE* pf = fopen("test.txt","r");//打开test.txt文件,进行读取,如果该文件不存在则出错
//这里判断一下打开文件是否成功,如果打开文件失败会返回NULL
if(pf == NULL)
{
//打开错误进行的操作
}
return 0;
}
3.fclose(关闭文件的函数)
1)库中的声明:
int fclose( FILE *stream );
2)使用举例:
int main()
{
FILE* pf = fopen("test.txt","r");//打开test.txt文件,进行读取,如果该文件不存在则出错
//这里判断一下打开文件是否成功,如果打开文件失败会返回NULL
if(pf == NULL)
{
//打开错误进行的操作
}
//括号内的参数就是要关闭的文件指针
fclose(pf);
//和free类似,并不会把pf置空,所以最好手动置空
pf = NULL;
return 0;
三、文件的顺序读写
文件的读取要借助于一些库中的函数,下面来理一理这些函数的用法和用途。
1.函数汇总
2.各函数的使用
1)fgetc
1.1)库中的声明
int fgetc( FILE *stream );
1.2)函数讲解:
- stream即是指向打开文件的一个文件指针
从文件中读取一个字符,返回其的ASCII码值,每次读取文件指针都会偏移到下一个字符的位置。
1.3)使用举例:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//输出test文件中的26个字母到pf文件指针,并打印
for (int i = 0; i < 26; i++)
{
printf("%c ", fgetc(pf));
}
printf("\n");
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
2)fputc
1.1)库中的声明
int fputc( int c, FILE *stream );
1.2)函数讲解:
- c表示所要写入文件的字符的ASCII码值
- stream即是指向打开文件的一个文件指针
把字符一个一个的写入到我们打开的文件中。
1.3)使用举例:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "w");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//以大写的形式写入26个英文字母到test文件中
for (int i = 0; i < 26; i++)
{
fputc(65 + i, pf);
}
printf("写入成功!\n");
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
3)fgets
1.1)库中的声明
char *fgets( char *string, int n, FILE *stream );
1.2)函数讲解:
- string是接收从文件中读取到的字符串存储的位置
- n表示最大的读取字符数
- stream即是指向打开文件的一个文件指针
从文件中读取n个字符到指定的存储位置,需要注意的是如果文件中一行只有10个字符,但是要读取20个字符的话,也只会把一行的字符读取完就结束了,而不会继续读取下一行的字符,而如果文件中一行有20个字符,要读取10个字符,调用一次fgets函数只会读取10个字符,再调用fgets函数将会从上次结束的位置继续读取,但仍然只会读取完这一行,就算n大于该行的字符数,也不会继续从下一行读取,需要注意的是实际读取到的字符数是n-1个,因为默认最后会读取一个‘\0’。
1.3)使用举例:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//将test文件中的文本行输入到str里
char str[20] = { 0 };
printf("%s", fgets(str, 50, pf));//实际读取到的个数是n-1个,最后一个默认放的'\0',并且一次只读取一行的文本
//printf("%s", fgets(str, 10, pf));
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
4)fputs
1.1)库中的声明
int fputs( const char *string, FILE *stream );
1.2)函数讲解:
- string表示所要写入文件的字符串
- stream即是指向打开文件的一个文件指针
1.3)使用举例:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "w");
if (NULL == pf)
{
perror("fopen");// return 1;
}
//将Hello World写入到test文件中
fputs("测试测试\n", pf);
printf("写入成功!\n");
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
5)fscanf
1.1)库中的声明
int fscanf( FILE *stream, const char *format [, argument ]... );
1.2)函数讲解:
- stream即是指向打开文件的一个文件指针,表示读取的数据来源于stream这个文件指针所指向的文件
- format表示以什么样的格式读取数据,类似于scanf的格式控制
按照一定的格式读取文件中的数据。
1.3)使用举例:
typedef struct S
{
char name[20];
int age;
float score;
}S;
int main()
{
S s;
//打开文件
FILE* pf = fopen("test.txt", "r");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//将test文件中的内容读取到结构体s中
fscanf(pf, "%s %d %f\n", s.name, &(s.age), &(s.score));
printf("%s %d %.2f\n", s.name, s.age, s.score);
//关闭文件
fclose(pf);
return 0;
}
6)fprintf
1.1)库中的声明
int fprintf( FILE *stream, const char *format [, argument ]...);
1.2)函数讲解:
- stream即是指向打开文件的一个文件指针,表示将程序中的数据按照一定个格式写入到stream这个文件指针所指向的文件中
- format表示按照什么样的格式写入文件,类似于printf的格式控制
按照一定的格式将程序中的数据写入到指定的文件当中。
1.3)使用举例:
typedef struct S
{
char name[20];
int age;
float score;
}S;
int main()
{
S s = { "张三",20,99.5f };
//打开文件
FILE* pf = fopen("test.txt", "w");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//将结构体s的内容写入到test文件中
fprintf(pf, "%s %d %.2f\n", s.name, s.age, s.score);
printf("写入成功!\n");
//关闭文件
fclose(pf);
return 0;
}
7)fread
1.1)库中的声明
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
1.2)函数讲解:
- buffer表示所要存储从文件中读取到的数据的存放地址
- size表示从文件中读取到的一个数据的所占内存的大小
- count表示一次从文件中读取的数据个数
- stream表示从stream这个文件指针所指向的文件中读取数据
从文件中读取合适的数据到所指定的位置,fread函数读取数据是由返回值的,每次正常读取会返回count,也就是你所设计的每次读取的数据个数,比如文件中有8个元素,每一次读取5个元素,第一次正常读取了5个元素,所以返回值是5,而此时文件指针向后偏移,再次读取时只会读取到3个元素,和设计的每次读取5个元素不匹配,此时返回值就会编程3,总的来说fread的返回值就是这一次读取到的数据的个数,如果文件中所有的数据都已经读取完毕,那么fread读取不到数据的话,返回值就是0,可以利用fread返回值的特点判断是否已经读取完文件中的数据了。
1.3)使用举例:
typedef struct S
{
char name[20];
int age;
float score;
}S;
int main()
{
S s;
char str[20];
//打开文件
FILE* pf = fopen("test.txt", "rb");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//将test文件中的内容加载到代码中
fread(&s, sizeof(S), 1, pf);
fread(str, sizeof(str), 1, pf);
printf("%s %d %.2f\n", s.name, s.age, s.score);
printf("%s\n", str);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
8)fwrite
1.1)库中的声明
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
1.2)函数讲解:
- buffer表示写入文件中的数据的来源
- size表示每个写入数据所占内存的大小
- count表示一次写入的数据个数
- stream表示将数据写入到stream这个文件指针所指向的文件
将数据按照设计的依此写入文件中,返回值和fread类似。
1.3)使用举例:
typedef struct S
{
char name[20];
int age;
float score;
}S;
int main()
{
S s = { "张三",20,99.5f };
char str[] = "hello world";
//打开文件
FILE* pf = fopen("test.txt", "wb");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//将结构体s的内容写入到test文件中
fwrite(&s, sizeof(S), 1, pf);
fwrite(str, sizeof(str), 1, pf);
printf("写入成功!\n");
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
四、文件的随机读写
前面介绍了文件的的顺序读写,借助于函数可以实现读写,但都是按照一定的顺序进行读写,做不到“指哪打哪”这种随机性,所以下面介绍几个通过偏移文件指针来实现随机读写的文件操作函数。
1.各函数的使用
1)fseek
1.1)库中的声明
int fseek ( FILE * stream, long int offset, int origin );
1.2)函数讲解:
- stream指向所打开的文件的文件指针
- offset偏移量
- origin从哪个位置开始偏移
根据文件指针的位置和偏移量来定位文件指针。
origin可以设置的参数:
- SEEK_SET:文件的起始位置
- SEEk_CUR:文件指针的当前位置
- SEEK_END:文件的结尾
也就是说参数origin设置成以上三种,可以做到从哪里开始偏移。
1.3)使用举例:
int main()
{
char str[50] = { 0 };
//打开文件
FILE* pf = fopen("test.txt", "w+");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//先写入数据
fputs("ABCDEFGHIJKL", pf);
//使用fseek,从开始位置偏移9个字节,此时pf指向J,输出JKL
fseek(pf, 9, SEEK_SET);
printf("%s\n", fgets(str, 4, pf));
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
2)ftell
1.1)库中的声明
long int ftell ( FILE * stream );
1.2)函数讲解:
- stream表示指向文件的文件指针
返回文件指针相对于起始位置的偏移量。
1.3)使用举例:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//先写入一些数据
fputs("Hello World", pf);
printf("写入成功\n");
//使用ftell,获取当前指针相对于起始位置的偏移量
//当前偏移量为0
int index = ftell(pf);
printf("%d\n", index);
//先使用fseek偏移文件指针,在计算其偏移量
fseek(pf, 0, SEEK_END);
printf("%d\n", ftell(pf));
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
3)rewind
1.1)库中的声明
void rewind ( FILE * stream );
1.2)函数讲解:
- stream表示指向文件的文件指针
让文件指针的位置回到文件的起始位置。
1.3)使用举例:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//使用ftell,获取当前指针相对于起始位置的偏移量
//当前偏移量为0
int index = ftell(pf);
printf("%d\n", index);
//先使用fseek偏移文件指针,在计算其偏移量
fseek(pf, 0, SEEK_END);
printf("%d\n", ftell(pf));
//使用rewind,让文件指针的位置回到文件的起始位置,然后输出文件指针此时的距离起始位置的偏移量
rewind(pf);
index = ftell(pf);
printf("%d\n", index);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
总结
温故而知新,写一篇文章以总结自己所知所学,也便于日后的复习所用,如果对你也能有哪怕一点点的帮助,那么这篇文章除了于我,那么也有了一定的价值,最后,感谢阅读,(EDG S12给我冲啊!争取双冠!!!!!!!!!!!!!)