目录
一、文件指针
二、文件的打开和关闭
文件打开方式:
fopen打开失败的原因:
三、流
四、文件顺序读写
1. fgetc(字符输入函数) fputc(字符输出函数)
2. fgets (文本行输入函数) fputs(文本行输出函数)
3.1 fprintf fscanf
3.2 scanf sprintf
4. fread fwrite(只适用于文件流)
一、文件指针
fopen打开文件会在内存中开辟一个文件信息区,用来存放文件的相关信息(文件名,文件状态及文件当前位置等)。这些信息存放在一个结构体变量中。这个结构体类型由系统声明,取名为FILE。
每打开一个文件系统会自动创建一个FILE结构体变量,并存入信息。
通过FILE*指针我们通过文件信息区中的内容访问文件。
二、文件的打开和关闭读取和写入之前应该先打开文件,使用结束要关闭文件。
文件打开方式:// 打开文件
FILE * fopen ( const char * filename , const char * mode );
filename 文件路径,只写文件名也可以。mode是打开方式。打开错误返回NULL。
返回值:文件信息区的起始地址
//关闭文件
int fclose ( FILE * stream);
文件打开方式 | 含义 | 如果指定文件不存在 |
"r"(只读) | 为了输入数据,打开一个已存在的文本文件 | 出错 |
"w"(只写) | 为了输出数据,打开一个文本文件 | 创建新文件 |
"a"(追加) | 向文本文件尾添加数据 | 创建新文件 |
"rb"(只读) | 为了输入数据,打开二进制文件 | 出错 |
"wb"(只写) | 为了输出数据,打开一个二进制文件 | 创建新文件 |
"ab"(追加) | 向二进制文件尾添加数据 | 出错 |
"r+"(读写) | 打开文本文件,读和写 | 出错 |
"w+"(读写) | 创建新文件,读和写 | 创建新文件 |
"a+"(读写) | 打开一个文件,在文件尾读写 | 创建新文件 |
"rb+"(读写) | 打开二进制文件,读和写 | 出错 |
"wb+"(读写) | 创建新二进制文件,读和写 | 创建新文件 |
"ab+"(读写) | 打开二进制文件,在文件尾读写 | 创建新文件 |
记忆小tip :带b的是二进制文件,带+是读写。都是带双引号的。
用"w"和"wb" (只写)只要打开文件会直接清空文件初始内容。
初始内容:
写内容到文件之后:
只打开文件但不写入:
打开文件后内容被清空。
使用fopen的时候
文件不存在:根据文件打开方式("w","r","a"...),有的会出错,有的会自动创建新文件。
fopen打开失败的原因:1.没显示文件扩展名
给文件起名为test.txt,但是没显示扩展名。那实际上这个文件名是test.txt.txt.
2.路径不对
写路径的时候要带两个\\ 防止将你的路径识别成转义字符。
上面这样就会打开失败。
这样就成功了。
三、流计算机传输数据的过程称为流。传输是有方向性的,需要输出流和输入流。
标准输入流:stdin 键盘
标准输出流:stdout 屏幕
标准错误流:stderr
⬆️这三个流只要程序运行起来就会默认打开。
四、文件顺序读写FILE * 是文件流。
功能 | 函数名 | 使用于 |
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本输入函数 | fgets | 所有输入流 |
文本输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
头文件:
int fgetc ( FILE * stream) ;
1️⃣参数:( 流 )
2️⃣返回值:一定要用int类型接收。成功读取,返回读取的字符,提升为整型。失败返回EOF。
int fputc ( int characyer , FILE * stream) ; //stream 是流的意思
1️⃣参数:( 想传输的字符 ,流 )
2️⃣返回值:写入失败返回EOF
例1:从键盘输入一个字符,输出到屏幕
# include
int main()
{
int ch = fgetc(stdin);//stdin 标准输入流 键盘 一定要用int类型接收
fputc(ch, stdout);//stdout 标准输出流 屏幕
return 0;
}
例2:把a~z写入文件
#include
int main()
{
//打开文件
FILE* pf = fopen("D:\ 222.txt", "wb");
if (pf == NULL)//判断是否打开成功
{
printf("fopen");
return 1;
}
//写文件
char ch = 'a';
for (ch = 'a'; ch >= 'a' && ch <= 'z'; ch++)
{
fputc(ch, pf);
}
//关闭文件
fclose(pf);
//指针置空防止野指针
pf = NULL;
return 0;
}
2. fgets (文本行输入函数) fputs(文本行输出函数)
头文件
char * fgets ( char * str , int num , FILE * stream );
1️⃣参数:(存入地址,个数,流)
2️⃣返回值:存入空间地址
int puts ( const char * str , FILE * stream );
1️⃣参数:(内容,流)
2️⃣返回值:成功是返回非负值,失败返回EOF
fputs:输出一行,想换行要给字符串带'\n',不然写到文件里就是一整行
1.带'\n'的版本
#include
int main()
{
//打开文件
FILE* pf = fopen("D:\\test.txt", "w");
if (pf == NULL)
{
printf("fopen\n");
return 1;
}
//写文件
fputs("abcdef\n", pf);
fputs("aaaaaa\n", pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
2.不带'\n'的版本
fputs:
文件内容:
#include
int main()
{
char arr[256] = "xxxxxxxxxxxxxxx";
//打开文件
FILE* pf = fopen("D:\\test.txt", "r");
if (pf == NULL)
{
printf("fopen\n");
return 1;
}
fgets(arr, 256, pf);
printf("%s", arr);//不用换行,因为在文件里第一行结尾是有换行符的
fgets(arr, 256, pf);
printf("%s", arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
只打印一行:
这里我们打印时没带换行符,但还是自动换行了。因为在文件里第一行没写满,要到下一行继续写内容,就必须给第一行结尾带上换行符。使用fgets时读取个数超出字符串长度,所以就读到了第一行字符串的'\n'。
fgets:只读n-1个字符,因为会预留最后一个位置放'fprintf fscanf'
如果设置个数少于字符串长度,没读到'\n'呢?
没有换行。
下面我们迎来一对万能选手。前面的一个是字符输入输出,一个文本行输入输出。
3.1 格式化输出头文件:
针对所有输出流的
int fprintf ( FILE * stream, const char * format, ... );函数: 格式化输入针对所有输入流的
int fscanf ( FILE * stream, const char * format, ... );函数: scanf sprintf
和printf和scanf用法差不多,就是多了个流。
例1:把一个结构体写到文件里
#include
struct S
{
char name[20];
int age;
double d;//分数
};
int main()
{
struct S s = { "张三",20,95.5 };
//打开文件
FILE* pf = fopen("D:\\test.txt","w");
if (pf == NULL)
{
printf("fopen");
return 1;
}
//写文件
fprintf(pf, "%s %d %lf", s.name, s.age, s.d);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
例2:从文件里读结构体,打印到屏幕上
#include
struct S
{
char name[20];
int age;
double d;//分数
};
int main()
{
struct S s = {0};
//打开文件
FILE* pf = fopen("D:\\test.txt","r");
if (pf == NULL)
{
printf("fopen");
return 1;
}
//写文件
fscanf(pf, "%s %d %lf", s.name, &(s.age), &(s.d));//和scanf使用时相似,需要取地址。因为s.name是个字符串,变量名就是首元素地址。所以s.name可以不取地址
//打印
fprintf(stdout, "%s %d %lf\n", s.name, s.age, s.d);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
附加学习以一个内容
3.2int sprintf ( char * str, const char * format, ... );
头文件:
把格式化数据转化成字符串:
int sscanf ( const char * s, const char * format, ...);⬇️要先转化才能提取
把字符串转换成格式化的数据(从字符串中提取信息):
fread fwrite(只适用于文件流)
#include
struct S
{
char name[20];
int age;
double d;//分数
};
int main()
{
struct S s = { "张三",20,90.5 };
char arr[256] = { 0 };//结构体转化成字符串,存到arr里
struct S tmp = { 0 };//从arr提取出数据放到结构体tmp里
//结构体转化成字符串
sprintf(arr, "%s %d %lf", s.name, s.age, s.d);
printf("%s\n", arr);
//提取出的数据放到tmp里
sscanf(arr, "%s %d %lf", tmp.name, &(tmp.age), &(tmp.d));
printf("%s %d %lf", tmp.name, tmp.age, tmp.d);
return 0;
}
4. 二进制输入:
头文件:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );二进制输出:size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );1️⃣返回值:实际写入的个数
2️⃣参数:(指针指向要写的数据,一个元素的大小,想要写入的元素个数,文件流)
例1:以二进制方式写入文件
#include
struct S
{
char name[20];
int age;
double d;//分数
};
int main()
{
struct S s = { 0 };
//读文件,以二进制方式读
FILE* pf = fopen("D:\\test.txt", "rb");
if (pf == NULL)
{
printf("fopen");
return 1;
}
fread(&s, sizeof(struct S), 1, pf);
printf("%s %d %lf\n", s.name, s.age, s.d);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
例2:以二进制方式读
文件里是二进制数据:
#include
int main()struct S
{
char name[20];
int age;
double d;//分数
};
{
struct S s = { 0 };
//读文件,以二进制方式读
FILE* pf = fopen("D:\\test.txt", "rb");
if (pf == NULL)
{
printf("fopen");
return 1;
}
fread(&s, sizeof(struct S), 1, pf);
printf("%s %d %lf\n", s.name, s.age, s.d);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)