赞
踩
写在前面:这篇大概是去年的十二份写的 但是忘记发了 最近又正好翻出来,小余学姐说 写都写了 干嘛不发呢 ,那就本着来都来了的原则 坐着歇会吧
使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。
磁盘上的文件是文件
缓冲文件系统中,关键的概念是“文件类型指针”,简称为文件指针
每个被使用的文件都在内存中开辟了一个相应文件信息区,用来存放文件相关信息(比如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构变量中的。该结构类型是系统声明的,取名FILE。
操作文件过程:
1.打开文件
2. 操作文件(读/写)
3. 关闭文件
FILE定义(Visual Studio2022 已封装)
#ifndef _FILE_DEFINED
#define _FILE_DEFINED
typedef struct _iobuf
{
void* _Placeholder;
} FILE;
#endif
FILE* (文件指针)返回文件起始地址
FILE* pf; //文件指针变量
定义 pf 是一个指向 FILE 数据类型的指针变量。可以使 pf 指向某个文件的文件信息区(是一个结构体变量,如上代码所示)。通过该文件信息区中的信息就能访问该文件。也就是说,通过文件指针变量能找到与它关联的文件。
ANSIC规定使用fopen
函数来打开文件,用fclose
来关闭文件
FILE * fopen ( const char * filename, const char * mode );
(文件名,文件的打开模式)
以下是常见的文件打开模式: )
( ps : 使用 “w” 进行写入的时候会覆盖之前原有的内容,追加请使用 “a” )
打开文件的基本形式:
FILE* pf = fopen(“test.txt”, “w”);
关闭文件:
fclose(pf);
pf = NULL;
文件打开关闭代码演示:
(没有test.txt文件记得先创建一个啦)
#include<stdio.h> #include<errno.h> #include<string.h> #include<stdlib.h> int main() { //打开文件 FILE* pf = fopen("test.txt", "w");//注意文件路径 if (pf == NULL) { printf("%s\n", strerror(errno)); //也可以使用 perror("fopen"); return (EXIT_FAILURE);// 或者也可以用 1 来代替 } //...对文件进行操作 //关闭文件 fclose(pf); pf = NULL;//让 pf 失忆 return 0; }
补充(关于prror)
void perror ( const char * str );
(详细说明建议参考Cplusplus)
1 ) fputc
int fputc ( int character, FILE * stream );
下面我们来尝试在文件中写入点什么,先搓代码
#include<stdio.h> #include<errno.h> #include<string.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "w"); if (pf == NULL) { printf("%s\n", strerror(errno)); return (EXIT_FAILURE); } //写文件 fputc('a', pf); //关闭文件 fclose(pf); pf = NULL; return 0; }
在上述代码中我们写入了个 a ,打开文件康康 ~
如果我们想要写字母 a ~ z 呢 ?我们也可以采用循环的方式写入
//写文件
char i;
for (i = 'a'; i <= 'z'; i++)
{
fputc(i, pf);
}
查看文本文件,Successful~
2 ) fgetc
int fgetc ( FILE * stream );
我们尝试读取刚刚我们写的文件,但是的但是,我们只能读取第一个字符
但是重复操作,我们就可以依次往下读取字符了(好麻烦)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
既然可以循环写入,那我们可以循环读出吗?当然可以!通过阅读
fgetc()
的用法,我们发现,当读取文件错误发生,该函数将会返回EOF
这样我们就知道怎么样去写一个输出循环了
//读文件
int ch = 0;
while ((ch = fgetc(pf)) != EOF)
printf("%c ", ch);
1 ) fputs
int fputs ( const char * str, FILE * stream );
(你要写的字符串,文件关联指针)
和刚刚fputc的区别在于是char
还是string
的读入
//写入
fputs("UNDERTALE", pf);
2 ) fgets
char * fgets ( char * str, int num, FILE * stream );
1 ) fprintf
看到
fprintf
我们不难想到printf
我们可以将两者结合对比,发现fprint
比printf
多了一个写入文件的参数
#include<stdio.h> #include<errno.h> #include<string.h> #include<stdlib.h> typedef struct S { char name[10]; int age; char gender[7]; char driveRobot[15]; }people; int main() { people one = { "Asuka", 14, "Female", "EVA2" }; FILE* pf = fopen("test.txt", "w"); if (pf == NULL) { perror("fopen"); return (EXIT_FAILURE); } //写入 fprintf(pf, "%s %d %s %s", one.name, one.age, one.gender, one.driveRobot); //关闭文件 fclose(pf); pf = NULL; return 0; }
2 ) fscanf
int fscanf ( FILE * stream, const char * format, … );
和scanf
相比也是多了个读取文件的参数
fscanf(pf, "%s %d %s %s", one.name, one.age, one.gender, one.driveRobot);
//输出查看是否正确(终端)(内心os:这样子做真的是忒麻烦...)
printf("%s %d %s %s", one.name, one.age, one.gender, one.driveRobot);
既然这样子做那么麻烦,那我们有什么办法去解决它吗,嘻嘻,有滴
任何一个 c 程序,只要运行起来就会默认打开三个流
- FILE* stdin — 标准输入流(键盘)(0)
- FILE* stdout — 标准输出流 (屏幕)(1)
- FILE* stderr — 标准错误流 (屏幕)(2)
那么针对于以上输出的情况,我们就可以使用输出流stdout
让我们想输出的内容直接呈现在屏幕上
fprintf(stdout, "%s %d %s %s", one.name, one.age, one.gender, one.driveRobot);
补充说明:写入存放文件的设备被称为外部设备(光盘、软盘、u盘…),每种外部设备都有着不同的读写方式,为了解决这个困难,计算机系统引入了流(是不是想到了参数
FILE* stream
)的概念。1
1 ) fwrite
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
FILE* pf = fopen("test.txt", "wb");// wb 以二进制的文件去写
if (pf == NULL)
{
perror("fopen");
return (EXIT_FAILURE);
}
//写
fwrite(&one, sizeof(people), 1, pf);// 1 (size_count) 写入的数量
打开文件,我们…看不懂了,哈哈。由于是二进制文件,所以显示出来的都是乱码。
虽然我们看不懂,但是我们可以使用一个能够读取二进制的函数读出我们想要的内容
2 ) fread
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
“怎么没有freadf 哈哈 不然就可以直接stdout了”
1 ) sprintf
int sprintf ( char * str, const char * format, … );
2 ) sscanf
int sscanf ( const char * s, const char * format, …);
sprintf
和sscanf
演示:
#include<stdio.h> #include<errno.h> #include<string.h> #include<stdlib.h> typedef struct S { char name[10]; int age; char gender[7]; char driveRobot[15]; }people; int main() { people one = { "Asuka", 14, "Female", "EVA2" }; people two = {0}; char buf[100] = { 0 }; //把 one 中的格式化数据转换成字符串放到 buf 中 sprintf(buf, "%s %d %s %s", one.name, one.age, one.gender, one.driveRobot); //打印 buf 内容,也相当于打印 one 结构体中的内容 //按照字符串形式打印 printf("%s\n", buf); //从字符串 buf 中获取一个格式化的数据到 two 中 //这里的 %s 不取地址是因为:数组名本身就是地址 sscanf(buf, "%s %d %s %s", two.name, &(two.age), two.gender, two.driveRobot); //按照格式化形式打印 printf("%s %d %s %s", two.name, two.age, two.gender, two.driveRobot); return 0; }
sprintf
和 fprintf
的区别fprintf()函数用于将格式化的数据写入文件中
sprintf()函数用于将格式化的数据写入字符串中2例如,在Python中,可以使用f-string来格式化字符串:
name = "Alice" age = 30 message = f"My name is {name} and I am {age} years old." print(message)
- 1
- 2
- 3
- 4
和 顺序 读写相反, 随机读取
根据文件的位置和偏移量来定位文件指针
int fseek ( FILE * stream, long int offset, int origin );
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );
让文件指针回到文件的起始位置
void rewind ( FILE * stream );
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在外存前转换。以ASCII字符的形式存储的文件就是文本文件。
流是指在计算机系统中,数据在内部设备(例如内存)和外部设备之间传输的一种方式。通过使用流,可以统一不同外部设备的读写方式,实现数据的高效传输和处理。
在计算机系统中,流被抽象成输入流(stdin)和输出流(stdout)两种形式(还有stderr)。输入流用于从外部设备读取数据到内部设备,输出流则用于将内部设备的数据写入到外部设备。通过流的抽象,程序可以通过统一的接口来读取和写入不同类型的外部设备。
流的概念使得程序员在处理数据时更加方便和灵活。无论是读取文件、网络通信还是与其他外部设备进行交互,都可以使用相似的流操作方式,简化了编程的复杂性。
总之,流是计算机系统中用于统一不同外部设备读写方式的抽象概念,通过流的操作,程序可以方便地进行数据传输和处理。 ↩︎
将格式化的数据写入字符串中,通常指的是使用字符串模板或格式化字符串
的方式,将变量、常量等数据按照一定的格式插入到字符串中。 ↩︎
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。