文章目录
文章目录
前言
今天给大家讲解一下C语言的文件操作相关知识
一.为什么使用文件
二.什么是文件
三.文件的打开和关闭
四.文件的顺序读写
一、为什么使用文件
在我们写好一个程序后,运行程序时,数据会存放在内存当中,而当我们退出程序之后数据随之在内存中消失,当下一次打开程序的时候之前写的数据全部丢失 (就好比你打游戏没存档了,是不是很鸡肋?)
所以我们要使用文件来存储之前用程序所写入的数据,使数据持久化。一般我们使用的方法为将数据存储到磁盘中或存放到数据库中等方式。
使用文件就可以将数据直接存放在电脑的硬盘上,实现了数据的持久化
二、什么是文件
1.程序文件
程序文件是包括源程序(后缀为.c),目标文件(后缀为.obj),可执行程序文件(后缀为.exe)。
2.数据文件
数据文件是程序中需要读写使用的数据,就是在程序运行中需要读取的数据文件或输出的数据文件。
3.文件名字
路径名字+文件主干名字+文件后缀
eg:c:\code\test.txt
三、文件的打开和关闭
1.文件指针
1). 每一个被使用的文件都会在内存中开辟一个相应的文件信息区,这个文件信息区存放着文件的相关信息(如文件名字,文件状态,文件位置等)。这些信息是放在一个结构体当中,系统将这个结构体重新命名为FILE类型。
在不同的编译器中FILE的内容会有所不同,但这并不重要,我们只需要知道这个结构体是存放有关文件的信息就好了。
eg:在vs2013中FILE的内容是这样的:
struct _iobuf {
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
};
typedef struct _iobuf FILE;
2). 知道了FILE类型,那么现在就可以知道文件指针是什么了,就是指向FILE的指针
FILE *pf;
2.文件的打开
文件的打开要使用到一个函数fopen()
这个函数的返回值是FILE *
第一个参数是被打开文件的名字,(输入时要带" “)。
第二个参数是打开方式,有如下几种方式:
在这里我们主要看"r"和"w”,"r"由上表中的翻译可以知道从文件读出信息,"w"由上表翻译可知是创建一个文件,将信息写入文件。
eg:
#include<stdio.h>
int main()
{
FILE* pf = fopen("code.txt", "w");
FILE* pf = fopen("D:soft\code.txt", "w");
if (pf == NULL)
{
perror("fopen");
return;
}//这条if语句是用来判断是否创建成功
return 0;
}
这样就在文件信息区开辟了一块区域存储code.txt文件的相关信息,打开方式是写入,并用一个pf文件指针指向这块区域。
补:1.第一个参数有两种写法,一种是不给路径的,正如第一行那样,这时文件夹会创建在当前.c文件所在文件夹中。另一种是给路径的,正如第二行那样,这时文件夹会创建在你给的路径底下
2.每次写入文件的时候都会覆盖之前文件里面的内容
3.文件的关闭
文件关闭的函数是fclose():
这里的stream参数是文件指针
eg:
#include<stdio.h>
int main()
{
FILE* pf = fopen("code.txt", "w");
if (pf == NULL)
{
perror("fopen");
return;
}
fclose(pf);
pf = NULL;//这句话是防止野指针的形成
return 0;
}
四.文件的顺序读写
1.fputc函数和fgetc函数
该函数是针对字符,输出函数,即对文件内容进行编辑,第一个参数是字符内容,第二个参数是文件指针。
#include<stdio.h>
int main()
{
FILE* pf = fopen("code.txt", "w");//写入数据所以这里是w
if (pf == NULL)
{
perror("fopen");
return;
}
int i = 0;
for (i = 0; i < 26; i++)
{
fputc('a' + i, pf);
}
fclose(pf);
pf = NULL;
return 0;
}
上面代码执行的结果就是在code.txt文件中写入数据a到z
这里可能有人会觉得,为什么是叫输出函数?这不是往文件中输入数据么?(我当初也有这样的疑问)其实是这样的,这个输入和输出针对的是程序和文件间的因为你要从程序输出数据到文件中保存,而你从文件中取数据到程序中,所以这时就叫输入函数了,主语是程序,所以输出和输入是针对程序而言的(懂了么?手动狗头)
来咯来咯,输入函数来了
这个参数还是文件指针,返回值是int,输入函数每当输入一位之后里面的指针会自动后移一位,然后下次输入的时候就是下一位了。
eg:
#include<stdio.h>
int main()
{
FILE* pf = fopen("code.txt", "r");//读取数据所以这里是r
if (pf == NULL)
{
perror("fopen");
return;
}
int i = 0;
int ret = 0;
for (i = 0; i < 26; i++)
{
ret=fgetc(pf);
printf("%c ", ret);
}
fclose(pf);
pf = NULL;
return 0;
}
当fgets函数中的指针指向数据结尾的时候就会返回EOF 所以此段代码还可以这样写:
#include<stdio.h>
int main()
{
FILE* pf = fopen("code.txt", "r");//读取数据所以这里是r
if (pf == NULL)
{
perror("fopen");
return;
}
int i = 0;
int ret = 0;
while((ret=fgetc(pf))!=EOF)
{
printf("%c ",ret);
}
fclose(pf);
pf = NULL;
return 0;
}
2.fputs函数和fgets函数
后面的fputs函数和fputc函数原理几乎一样,只不过针对的是字符串(聪明的你一定看一眼就秒杀了),我就不讲了。
#include<stdio.h>
int main()
{
FILE* pf = fopen("code.txt", "w");
if (pf == NULL)
{
perror("fopen");
return;
}
int i = 0;
fputs("i'm a bit\n", pf);
fputs("i'll be rich\n", pf);
fclose(pf);
pf = NULL;
return 0;
}
fgets函数需要讲,str是程序中被输入的数组地址,num是传入数据大小,stream还是文件指针。
eg:(读取的时候是一行一行的读取,有多少行读取多少次)
#include<stdio.h>
int main()
{
FILE* pf = fopen("code.txt", "r");
if (pf == NULL)
{
perror("fopen");
return;
}
int i = 0;
char arr[20] = "####################";
fgets(arr,20,pf);
printf("%s", arr);
fgets(arr, 20, pf);
printf("%s", arr);
fclose(pf);
pf = NULL;
return 0;
}
这是第一次读取arr数组发生的变化
3.fprintf函数和fscanf函数
这里的stream是文件指针,后面的参数是结构体内容如下代码所示
#include<stdio.h>
struct s
{
char name[20];
char sex[10];
int age;
};
int main()
{
struct s stu = { "zhangsan","male",21 };
FILE* pf = fopen("code.txt", "w");
if (pf == NULL)
{
perror("fopen");
return;
}
fprintf(pf,"%s %s %d", stu.name, stu.sex, stu.age);
fclose(pf);
pf = NULL;
return 0;
}
fscanf和fprintf几乎一样,参见代码:
#include<stdio.h>
struct s
{
char name[20];
char sex[10];
int age;
};
int main()
{
FILE* pf = fopen("code.txt", "r");
if (pf == NULL)
{
perror("fopen");
return;
}
struct s stu = {0};
fscanf(pf, "%s %s %d", stu.name, stu.sex, &(stu.age));
printf("%s %s %d", stu.name, stu.sex, stu.age);
fclose(pf);
pf = NULL;
return 0;
}
关于输入流和输出流的补充
任何的程序只要开始执行都会默认开启:
1.标准输入流-stdin(对应键盘)
2.标准输出流-stdout(对应屏幕)
3.标准错误流-stderr(对应屏幕)
scanf等价于fsanf(stdin,);
printf等于fprintf(stdout,);
3.fwrite函数和fread函数
ptr为一个指针指向被写入的地址
size为每一个元素的大小
count为元素个数
stream为文件指针
#include<stdio.h>
struct s
{
char name[20];
char sex[10];
int age;
};
int main()
{
struct s stu = { "zhangsan","male",99 };
FILE* pf = fopen("code.txt", "wb");//因为这里是二进制输入所以这里是wb
if (pf == NULL)
{
perror("fopen");
return;
}
fwrite(&stu, sizeof(struct s), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
这里是不是觉得有问题?
low low low因为是二进制语言储存,是机器语言,机器懂,你不懂(手动狗头)不信接着往下看:
fread的参数出了第一个被改为被写入的结构体的地址,其余都和fwrite一样。
直接上代码:
#include<stdio.h>
struct s
{
char name[20];
char sex[10];
int age;
};
int main()
{
struct s stu = { 0 };
FILE* pf = fopen("code.txt", "rb");//二进制读取所以是rb
if (pf == NULL)
{
perror("fopen");
return;
}
fread(&stu, sizeof(struct s), 1, pf);
printf("%s %s %d", stu.name, stu.sex, stu.age);
fclose(pf);
pf = NULL;
return 0;
}
正常读取了文件里的数据。
五.总结
今天给大家介绍了为什么要使用文件,以及什么是文件,什么是文件信息区,以及怎样用输入输出函数来对文件中的内容进行读取和写入,希望对你有所帮助,谢谢!