文件1.0
文件的详细介绍
引子
文件.在我们前面学习通讯录时,程序运行起来时,可以给通讯录增删查改,但此时数据是存放在内存中,当程序退出时,通讯录的数据就消失了。
就很难受,为了使得数据持久化,我们就应该把数据存放在磁盘文件,存放到数据库等方式,磁盘上关机了重启还会在,使数据持久化,因此就需要用到文件
目录
文件
目录
文件
1.什么是文件
2.文件名
3.文件指针(文件的打开与关闭)
4.文件的使用
1 什么是文件
在磁盘上所有的东西都是文件,c盘包括桌面的,
但一般在程序设计时,分两种:程序文件和数据文件(从文件的功能进行分类的)
程序文件有源程序文件.c,目标文件.obj,可执行文件.exe
数据文件,我们写的数据
2.文件名
文件名,一个文件有唯一的文件标识。便于用户使用和识别(绝对路径)
文件名包含3个部分:文件路径+文件名主干+文件名后缀
如c:\code\test.txt,其中c:\code\是路径名,test叫文件主干名,.txt叫文件的后缀2
3.文件指针
4.文件指针(文件的打开与关闭)
每个被使用的文件都开辟了一个相应的文件信息区,用于存放文件的相关信息,
(如文件的名字,文件状态及文件当前的位置)这些信息都保持在一个结构体变量中,该结构体类型名叫FILE
一般用FILE型指针来维护FILE结构的变量,这样使用起来更加方便
FILE* pf,pf是指向FILE型的变量,可以使用pf来指向某个文件信息区,通过文件信息区中的信息就可以访问该文件,即可以通过文件指针变量找到与他相关的文件,
4.文件的使用
文件在读写之前首先要打开文件fopen,在文件使用完之后要关闭文件fclose,fopen返回失败会返回一个空指针,因此每次使用都要判断
其中fopen原型是FILE * fopen(const char * path, const char * mode);
const char * path是使用的路径,即要在哪个文件中使用
const char * mode是fopen的打开形式
常见的模式有”r“,(read)以只读方式打开文件,该文件必须存在。
”w“(write)打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
例如
1.0
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *pf=fopen("tst.dat", "w");*///"test.dat"是文件名,"w"是打开方式(以写的形式进行创建)(只写)“w”为了 输出数据,打开一个文件,如果指定文件不存在,就新建一个(在此文件中开辟)
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件(不想要了)
fclose(pf);
pf = NULL;//可类比动态内存开辟,补不置成空指针就会报错
return 0;
}
1.1
#include<stdio.h>
int main()
{
FILE *pf=fopen("D:\\2021\\class\\test.7\\test.dat", "w");//如果文件并不是在此文件下创建的化,同样也不会运行成功,但使用绝对路径是可以的
//,单斜杠情况下会将后面理解为转义字符,因此都要使用双斜杠,用于将\打印出来
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件(不想要了)
fclose(pf);
pf = NULL;//
return 0;
}
1.3
#include<stdio.h>
int main()
{
FILE *pf = fopen("tst.dat", "r");//以读的方式打开
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件(不想要了)
fclose(pf);
pf = NULL;//可类比动态内存开辟,
return 0;
}
文件的顺序读写
:流,高度抽象的概念,,我们写的程序有时想放屏幕,硬盘,u盘,光盘,网络,程序要操作各种硬件,也就需要各种的读写方式,因此在程序与硬件中抽象出流这个层次
我们只有把数据放到流里面去,写文件可以理解为文件流,
c语言程序运行起来,就默认打开了3个流
stdin-标准输入流--键盘, stdout标准输出流--屏幕, stderr--标准错误流--屏幕,类型都是FILE*的使用哪个流就在哪个流输出输入
代码2.0
#include<stdio.h>
int main()
{
FILE *pf = fopen("test.dat", "w");//以w的形式打开,即使原来有内容也会清空掉,
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fputc('b', pf);//文件字符输入,
fputc('i', pf);
fputc('t', pf);//便会向test.dat文件中输入bit
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}
2.1
#include<stdio.h>
int main()
{
fputc('c', stdout);//便在屏幕上打印了c这字符
fputc('b', stdout);
fputc('a', stdout);
return 0;
}
2.2.
#include<stdio.h>
int main()
{
FILE *pf = fopen("test.dat", "r");//以w的形式打开,即使原来有内容也会清空掉,
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件,fgetc从文件首字符中一个一个读取
//int ret=fgetc(pf);//从文件流里面读一个字符,可以从文件,也可以从标准输入流中,文件字符输入,如果读取正常,会返回此字符的ascll值,如果读取失败,会返回EOF(-1)
//printf("%c", ret);
//ret = fgetc(pf);
//printf("%c", ret);//读取的都是test.dat
int ret = fgetc(stdin);//从标准屏幕输入流里面读一个字符,可以从文件,也可以从标准输入流中,文件字符输入,如果读取正常,会返回此字符的ascll值,如果读取失败,会返回EOF(-1)
printf("%c", ret);
ret = fgetc(stdin);
printf("%c", ret);//读取的都是test.dat,文件结束就会输出EOF为-1
fclose(pf);
pf = NULL;
return 0;
}
我们不仅可以一个字符一个字符的输入与输出,
我们也可以一行一行的输入与输出
可以用到fgets,fputs
#include<stdio.h>
int main()
{
FILE*pf = fopen("test.dat", "w");//以写的形式打开
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件-按行写
fputs("abcdef\n",pf);//s-string写字符串打个\n就可以换行,pf是要写的文件流
fputs("ghijk\n", pf);
//用完关闭文件
fclose(pf);
pf = NULL;
return 0;
}
#include<stdio.h>
int main()
{
char arr[10] = { 0 };
FILE*pf = fopen("test.dat", "r");//以读的形式打开
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件-按行读
fgets(arr, 4, pf);//fgets(const char*string,const int n,const stream),n是可以读的最大字符,但多了一个\0n要+1
printf("%s\n", arr);//读完从c后开始读
fgets(arr, 4, pf);//最多读3个
printf("%s\n", arr);
//用完关闭文件
fclose(pf);
pf = NULL;
return 0;
}
我们接下来介绍一下fprintf,fscanf,sscanf,sprintf
#include<stdio.h
struct s
{
char age[10];
int a;
float f;
};
int main()
{
struct s a = { "hello",20,5.5f };
char buf[100] = { 0 };
struct s tmp = { 0 };
//sprintf是把格式化的数据转化成字符串,
sprintf(buf, "%s %d %f", a.age, a.a, a.f);
printf("%s\n", buf);
//从buf这个字符串中还原出一个结构体
//从字符串中读出格式化的数据
sscanf(buf, "%s %d %f", tmp.age, &tmp.a, &tmp.f);
printf("%s %d %f", tmp.age, tmp.a, tmp.f);
return 0;
}
fprintf(FILE *stream, const char *format,......)除去前面的流,后都和printf一样,
struct a
{
char arr[10];
int num;
float sc;
};
int main()
{
struct a s = { "abcd",10,5.5f };
FILE* pf = fopen("test.dat", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fprintf(pf, "%s %d %f", s.arr, s.num, s.sc);//格式化输出,写入pf文件流,
return 0;
}
fscanf同scanf多了前面的流
int main()
{
struct a s = { "abcd",10,5.5 };
FILE* pf = fopen("test.dat", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fscanf(pf, "%s %d %f", s.arr, &(s.num), &(s.sc));//格式化输出,写入pf文件流
printf("%s %d %f", s.arr, s.num, s.sc);
return 0;
}
fwrite二进制输出 (const void *ptr, size_t size, size_t nmemb, FILE *stream)
把 ptr 所指向的数组中的数据写入到给定流 stream 中
size这是要被写入的每个元素的大小,以字节为单位
nmemb -- 这是元素的个数,每个元素的大小为 size 字节
int main()
{
struct a s = { "abcd",10,5.5 };
FILE* pf = fopen("test.dat", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fwrite(&s, sizeof(struct a), 1, pf);//二进制输出,写入pf文件流
fclose(pf);
pf = NULL;
return 0;
}
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)与fwrite等同二进制输出
int main()
{
struct a s = { "abcd",10,5.5 };
FILE* pf = fopen("test.dat", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fread(&s, sizeof(struct a), 1, pf);//二进制输入,读出pf文件流
printf("%s %d %f", s.arr, s.num, s.sc);
fclose(pf);
pf = NULL;
return 0;
}