目录
10.scanf / fscanf / sscanf ; printf / fprintf / sprintf 的对比
一:文件
磁盘上的文件叫做文件
在程序设计中,一般情况下的文件(从文件功能分类)指的是:程序文件和数据文件
1.程序文件
包含:
源程序文件(后缀为 .c )
目标文件(windows环境后缀为 .obj)
可执行程序(windows环境后缀为 .exe)
2.数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
3.文件名
二:文件的打开和关闭
1.打开文件
2.文件操作(读/写)
3.关闭文件
1.文件指针
缓冲文件系统中,关键的概念是 “ 文件类型指针 ” ,简称 “ 文件指针 ” 。每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名 字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统 声明的,取名FILE.不同的 C 编译器的 FILE 类型包含的内容不完全相同,但是大同小异。每当打开一个文件的时候,系统会根据文件的情况自动创建一个 FILE 结构的变量,并填充其中的信息, 使用者不必关心细节。一般都是通过一个 FILE 的指针来维护这个 FILE 结构的变量,这样使用起来更加方便。
2.文件的打开和关闭
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。
文件使用方式
|
含义
|
如果指定文件不存在
|
---|---|---|
“r”
(只读)
|
为了输入数据,打开一个已经存在的文本文件
|
出错
|
w”
(只写)
|
为了输出数据,打开一个文本文件
|
建立一个新的文件
|
“a”
(追加)
|
向文本文件尾添加数据
|
建立一个新的文件
|
“rb”
(只读)
|
为了输入数据,打开一个二进制文件
|
出错
|
“wb”
(只写)
|
为了输出数据,打开一个二进制文件
|
建立一个新的文件
|
“ab”
(追加)
|
向一个二进制文件尾添加数据
|
出错
|
“r+”(读写)
|
为了读和写,打开一个文本文件
|
出错
|
“w+”
(读写)
|
为了读和写,建议一个新的文件
|
建立一个新的文件
|
“a+”
(读写)
|
打开一个文件,在文件尾进行读写
|
建立一个新的文件
|
“rb+”
(读写)
|
为了读和写打开一个二进制文件
|
出错
|
“wb+”
(读写)
|
为了读和写,新建一个新的二进制文件
|
建立一个新的文件
|
“ab+”
(读写)
|
打开一个二进制文件,在文件尾进行读和写
|
建立一个新的文件
|
<1>:fopen --- 打开文件
FILE *fopen( const char *filename, const char *mode );
// 文件名 打开方式
头文件:#include<stdio.h>
<2>:fclose --- 关闭文件
int fclose( FILE *stream );
头文件:#include<stdio.h>
<3>:示例
直接指定名字 --- 相对路径 --- 在一个工程下创建的
以只写的方式打开一个 test.txt 文件:
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "w");
// w --- 只写,为了输出数据,打开一个文本文件,若指定文件不存在,则创立一个新的文件。
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件
fclose(pf);
pf = NULL;//防止pf变成野指针
return 0;
}
程序未进行时:
程序进行后:
此时,没有 test.txt,这个文件,以只读的方式该文件打开下述代码:
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
// r --- 只读,为了输入数据,打开一个已经存在的文本文件,如果指定文件不存在,则出错。
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件
fclose(pf);
pf = NULL;//防止pf变成野指针
return 0;
}
运行结果为:
在桌面创建一个新的文件 --- 使用绝对路径
绝对路径 --- 右击 -> 更多选项 -> 属性 -> 位置
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("某文件的绝对路径\\test.txt", "r");
// r --- 只读,为了输入数据,打开一个已经存在的文本文件,如果指定文件不存在,则出错。
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件
fclose(pf);
pf = NULL;//防止pf变成野指针
return 0;
}
若删除桌面上的 test.txt 文件,进行下述代码:
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("C:\\Users\\王毓曼\\Desktop\\test.txt", "w");
// w --- 只写,为了输出数据,打开一个文本文件,若指定文件不存在,则创立一个新的文件。
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件
fclose(pf);
pf = NULL;//防止pf变成野指针
return 0;
}
程序运行成功后,会在桌面上生成一个 test.txt 文件。
若桌面上的 test.txt 文件没有删除,并且其中有内容,则进行上述代码时:
程序运行前:
程序成功运行后:
三:文件的顺序读写
顺序读写函数介绍:
功能 | 函数名 | 适用于 |
---|---|---|
字符输入函数
|
fgetc
|
所有输入流
|
字符输出函数
|
fputc
|
所有输出流
|
文本行输入函数
|
fgets
|
所有输入流
|
文本行输出函数
|
fputs
|
所有输出流
|
格式化输入函数
|
fscanf
|
所有输入流
|
格式化输出函数
|
fprintf
|
所有输出流
|
二进制输入
|
fread
|
文件
|
二进制输出
|
fwrite
|
文件
|
1.fputc --- 向文件写入一个字符
示例:将 26 个英文字母写入文件
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//把 26 个字母写到文件中
int i = 0;
for (i = 0; i < 26; i++)
{
fputc('a' + i, pf);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
程序运行成功后,效果为
2.fgetc --- 输出文件中的字符
每读取一个,文件指针会向后走一步,当 26 个字母读取完成后,此时指针已指向下一个位置。不可以使用 pf++。
// fgetc 读文件操作
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
//只读,为了输入数据,打开一个已经存在的文本文件,如果指定文件不存在,则出错。
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
//把 26 个字母写到文件中
int i = 0;
int ch = 0;
for (i = 0; i < 26; i++)
{
ch = fgetc(pf);
printf("%c ", ch);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
3.fputs --- 向文件写入一个字符串
// fputs 写一行数据
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
// 向文件中写入内容
fputs("Hello World\n", pf);
//需要自己添加换行操作
fputs("hahahahahaha\n", pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
程序运行成功后,文件为:
4.fgets --- 输出文件中的字符串(可以指定个数)
// fgets 读一行数据
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r");//默认工程路径
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读数据
char arr[20];
fgets(arr,6,pf);
printf("%s\n", arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
效果为:
会少读一个字符,放入一个 '\0'。
5.fprintf --- 向文件写入格式化的内容
//格式化的读写
// fprintf --- 写入
#include<stdio.h>
struct S
{
int n;
double c;
char arr[20];
};
int main()
{
struct S s = { 200,2.3,"wangwu" };
//打开文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fprintf(pf,"%d %lf %s\n",s.n,s.c,s.arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
程序成功运行后,文件为:
6.fscanf --- 读取文件中的格式化内容
// fscanf 函数
//对比 scanf 函数
#include<stdio.h>
struct S
{
int n;
double c;
char arr[20];
};
int main()
{
struct S s = { 200,2.3,"wangwu" };
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fscanf(pf,"%d %lf %s",&s.n,&s.c,s.arr);
printf("%d %lf %s\n", s.n, s.c, s.arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
效果为:
7.fwrite --- 二进制的写文件
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
// buffer --- 指向要写入数据的指针
// size --- 项大小(已字节为单位)
// count --- 要写的最大条目数
// stream --- 指向FILE结构的指针
//fwrite --- 二进制的写文件
#include<stdio.h>
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { "wabgwu",23,89.2 };
FILE* pf = fopen("ceshi.asd", "wb");
// wb --- 为了输出数据,打开一个二进制文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fwrite(&s, sizeof(struct S), 1, pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
当程序运行成功后,文件为:
8.fread --- 二进制的读文件
//fread --- 二进制的读文件
#include<stdio.h>
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("ceshi.asd", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fread(&s,sizeof(struct S),1,pf);
printf("%s %d %f\n", s.name, s.age, s.score);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
效果为:
9.流
#include<stdio.h>
struct S
{
int n;
double c;
char arr[20];
};
int main()
{
int ch = fgetc(stdin);//文件 --- 标准输入流 -- stdin
printf("%c\n", ch);
fputc('a', stdout);//文件 --- 标准输出流 -- stdout
fputc('b', stdout);
fputc('c', stdout);
printf("\n");//换行
struct S s = { 200,3.1415,"hahaha" };
fprintf(stdout, "%d %lf %s\n", s.n, s.c, s.arr);
struct S sa = { 0 };
fscanf(stdin, "%d %lf %s", &(sa.n), &(sa.c), sa.arr);//向 sa 中输入数据
fprintf(stdout, "%d %lf %s\n", sa.n, sa.c, sa.arr);
return 0;
}
效果为:
10.scanf / fscanf / sscanf ; printf / fprintf / sprintf 的对比
#include<stdio.h>
struct S
{
int n;
double c;
char arr[20];
};
int main()
{
struct S s = { 100,2.45,"hahahage" };
//把一个结构体转换成字符串
char arr[100] = { 0 };
sprintf(arr,"%d %lf %s\n", s.n, s.c, s.arr);
//将后面的数据 ( s.n ) 转换为一种格式 ( %d ),放到arr这个字符串中去
printf("字符串的数据:%s\n", arr);
struct S sa = { 0 };
//把一个结构体转化成对应的格式化数据
sscanf(arr, "%d %lf %s", &(sa.n), &(sa.c), sa.arr);
printf("格式化的数据:%d %lf %s\n", sa.n, sa.c, sa.arr);
return 0;
}
效果为: