1. 为什么使用文件
使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。
2. 什么是文件
磁盘上的文件是文件。 但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。
2.1 程序文件
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境 后缀为.exe)。
2.2 数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件, 或者输出内容的文件。
本章讨论的是数据文件。
在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显 示器上。
其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理 的就是磁盘上文件。
2.3 文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名。
3. 文件的打开和关闭
3.1 文件指针
3.2 文件的打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。
我们来看看这两个函数的使用。
打开文件
FILE * fopen ( const char * filename, const char * mode );

文件访问模式(打开方式):

关闭文件
int fclose ( FILE * stream );
直接找到该文件指针,对其关闭就可以了。
同时注意的是:关闭后,将该指针置空,防止以后不小心用到,形成野指针。
现在,我们来通过示例来感受一下:
示例:
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("code_test.txt", "w");
if (pf == NULL)
{
perror("fopen");//如果文件打开失败,打印失败原因
return 1;
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
运行上述代码,将会以“w”只写的方式打开一个 “code_test.txt”的文件,如果没有此文件,将会先建立一个这样的新文件,再打开。这一切都是在该工程目录的路径下。
运行前:

运行后:

我们可以看到,文件被创建出来,因为没有进行写入操作,所以,什么内容都没有,是空的。
下面,我们来看看如何读写。
4 文件的顺序读写
关于文件的顺序读写会用到以下几种函数:

4.1 fputc
int fputc ( int character, FILE * stream );
int character———需要输入的字符,FILE * stream——文件指针
现在,我们用它往文件中写入26个英文字母
代码:
//fputc
//int fputc ( int character, FILE * stream );
//成功:返回写入的字符值
//失败:返回EOF
void test5()
{
FILE* pf = fopen("code_test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return;
}
//写入26英文字母
for (int i = 0; i < 26; i++)
{
printf("%c ", fputc('a' + i, pf));//根据返回值,同时打印26英文字母
}
fclose(pf);
pf = NULL;
}
运行前,code_test文件中是空白的:

运行后,就会写入26个英文字母:

4.2 fgetc
int fgetc ( FILE * stream );
利用fgetc函数,就可以从刚才的文件中读到写入的26个英文字母
代码:
//fgetc
//int fgetc ( FILE * stream );
void test6()
{
FILE* pf = fopen("code_test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return;
}
//读取写入的26个英文字母
char temp = 0;
for (int i = 0; i < 26; i++)
{
temp=fgetc(pf);
printf("%c ", temp);
}
//关闭文件
fclose(pf);
pf = NULL;
}
运行结果:

4.3 fputs和fgets
前面的是输入单个字符,现在我们来输入一行字符串
int fputs(const char *str, FILE *stream)
把字符串写入到指定的流 stream 中,但不包括空字符。
代码:
//fputs---写一行数据
void test1()
{
//打开文件
//相对路径(在工程路径中)
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return ;
}
//写文件
fputs("hello world", pf);
//关闭文件
fclose(pf);
pf = NULL;
}
现在利用fgets将写入的信息读出来:
char *fgets(char *str, int n, FILE *stream)
从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
示例:
//fgets——读入一行数据
//注意:1.遇到换行符,停止读入。
// 2.读取(num-1)个字符
void test2()
{
char str[100] = { 0 };
//打开文件
//相对路径(在工程路径中)
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return ;
}
//读文件
fgets(str, 10, pf);
printf("%s\n", str);
//关闭文件
fclose(pf);
pf = NULL;
}
我们只读取了9个字符,所以应该读到:hello wor这9个字符。
运行结果:![]()
4.4 fscanf和fprintf
那如果,要写入不同类型的数据呢?
比如:结构体数据如何?
这就需要用到这两个函数:fscanf和fprintf
代码:
struct S
{
char name[20];
int age;
};
void test3()
{
struct S s = { "张三",20 };
//打开文件
//相对路径(在工程路径中)
FILE* pf = fopen("test1.txt", "w");
if (pf == NULL)
{
perror("fopen");
return;
}
//写文件
fprintf(pf, "%s %d", s.name,s.age);
//关闭文件
fclose(pf);
pf = NULL;
}
//
void test4()
{
struct S s1 = { 0 };
//打开文件
//相对路径(在工程路径中)
FILE* pf = fopen("test1.txt", "r");
if (pf == NULL)
{
perror("fopen");
return;
}
//读文件
fscanf(pf, "%s %d", s1.name,&s1.age);
printf("%s %d", s1.name, s1.age);
//关闭文件
fclose(pf);
pf = NULL;
}

如上图所示,代码运行前,文件中是空白的,运行结束后,将信息写入到文件中去。
5. 文件的随机读写
前面提到的是顺序读写,因为像fgetc这样的函数,他只能一个一个的往下读,是无法返回的。比如说:利用fgetc读到一半想要从头开始,这是做不到的。
那如何让我们想读哪就读哪,这就需要以下函数
5.1 fseek
根据文件指针的位置和偏移量来定位文件指针。
int fseek ( FILE * stream, long int offset, int origin );
offset——相对于origin参数位置的偏移量
origin——表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
来看示例:
我们还是利用前面写入了26个英文字母的文件来读取。
void test7()
{
FILE* pf = fopen("code_test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return;
}
//读取写入的26个英文字母
char temp = 0;
//a
temp = fgetc(pf);
printf("%c\n", temp);
//b
temp = fgetc(pf);
printf("%c\n", temp);
//c
temp = fgetc(pf);
printf("%c\n", temp);
//fgetc每读一次,文件指针向后偏移一位
//通过fseek再读a
fseek(pf, -3, SEEK_CUR);//指针-3回到a的位置
temp = fgetc(pf);
printf("%c\n", temp);
//关闭文件
fclose(pf);
pf = NULL;
}

5.2 ftell
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );
比如上面的代码,我们读到字符c时,忘记偏移量是多少了,就可以利用ftell函数来看一下此时的偏移量。
代码:
void test7()
{
FILE* pf = fopen("code_test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return;
}
//读取写入的26个英文字母
char temp = 0;
//a
temp = fgetc(pf);
//b
temp = fgetc(pf);
//c
temp = fgetc(pf);
//ftell----返回文件指针相对于起始位置的偏移量
int move = ftell(pf);
printf("%d\n", move);//3
//关闭文件
fclose(pf);
pf = NULL;
}
运行结果:![]()
5.3 rewind
让文件指针的位置回到文件的起始位置
void rewind ( FILE * stream );
当我们想从头开始读时,利用rewind就可以了。
示例:
void test7()
{
FILE* pf = fopen("code_test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return;
}
//读取写入的26个英文字母
char temp = 0;
//a
temp = fgetc(pf);
//b
temp = fgetc(pf);
//c
temp = fgetc(pf);
//rewind-----让文件指针的位置回到文件的起始位置
rewind(pf);
int move = ftell(pf);
printf("%d\n", move);//0----偏移量
//关闭文件
fclose(pf);
pf = NULL;
}
![]()
小结
文件操作内容还有很多,在这里就不依次介绍。谢谢观看!
484

被折叠的 条评论
为什么被折叠?



