相信很多初学 C 语言的老铁,看到 C 语言文件的时候,对其中所用到的函数概念会比较模糊,本篇文章将会对其进行解答与演示。
注:本文所有用到的库函数(fgetc、fopen、fclose等……函数参数的细节等都能在下面的网站链接所找到)
本文所用到的全部代码:C 语言文件操作
本文所用到的网站链接:C 语言cplusplus
目录
文件
磁盘上的文件是文件。
但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。
- 程序文件:包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
- 数据文件:文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如:D:\Code\blog.c
为了方便起见,文件标识常被称为文件名。
文件指针
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE。
//例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:
struct _iobuf {
char *_ptr; //文件输入的下一个位置。
int _cnt; //当前缓冲区的相对位置。
char *_base; //指针的基础位置(即是文件的起始位置)。
int _flag; //文件标志。
int _file; //文件的有效性验证。
int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取。
int _bufsiz; //缓冲区的大小。
char *_tmpfname; //临时文件名。
};
typedef struct _iobuf FILE;
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
下面我们可以创建一个FILE*的指针变量:
FILE* pf;
//定义pf是一个指向FILE类型数据的指针变量。
//可以使pf指向某个文件的文件信息区(是一个结构体变量)。
//通过该文件信息区中的信息就能够访问该文件。
//也就是说,通过文件指针变量能够找到与它关联的文件
文件的关闭与打开
之前有一个故事说:“把大象装进冰箱总共分几步?”
- 把冰箱门先打开
- 把大象塞进去
- 关闭冰箱门
文件的操作也跟其步骤类似,我们先要把文件的“门”打开,在文件里面做完操作之后要把文件的“门”关闭上。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。
ANSIC 规定使用 fopen 函数来打开文件,fclose 函数 来关闭文件。
//打开
FILE * fopen ( const char * filename, const char * mode );
文件使用方式 | 含义 | 如果指定文件不存在 |
“r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
//关闭
int fclose ( FILE * stream );
代码演示:
int main()
{
FILE* pf = fopen("file.txt", "w");
if (pf != NULL)
{
//文件操作
//………………
//文件关闭
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
注:pf = NULL 的原因:
通过在对代码的运行我门在项目文件里面发现了所创建的 txt 文件:
文件顺序的读写
fgetc 和 fputc
fputc 字符输入函数
int main()
{
FILE* pf = fopen("file.txt", "w");
if (pf != NULL)
{
//写文件
char ch = 0;
for (ch = 'a'; ch <= 'z'; ch++)
{
fputc(ch , pf);
fputc(' ', pf);
}
//文件关闭
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
通过在对代码的运行我门在项目文件里面发现所创建的 txt 文件 里面有了 a - z 的字母:
fgetc 字符输出函数
int main()
{
FILE* pf = fopen("file.txt", "r");
if (pf != NULL)
{
//读文件
char ch = 0;
while ((ch = fgetc(pf)) != EOF)
{
printf("%c", ch);
}
//ch = fgetc(pf);
//printf("%c", ch);//a
//文件关闭
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
fgets 和 fputs
fputs 文本输入函数
int main()
{
FILE* pf = fopen("file.txt", "w");
if (pf != NULL)
{
//写文件
fputs("hunter ", pf);
char str[] = "yyds";
fputs(str, pf);
//文件关闭
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
fgets 文本输出函数
int main()
{
FILE* pf = fopen("file.txt", "r");
if (pf != NULL)
{
//读文件
char arr[100] = { 0 };
fgets(arr, 100, pf);
printf("%s", arr);
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
注:读取 n-1个字符 ,所以如果上述代码 我只想读取 h 字符的话,在上述图片的部分应该写 2
fscanf 和 fprintf
fprintf 格式化输出函数
int main()
{
struct hunter yyds = { "hunteryyds",20,1.88 };
FILE* pf = fopen("file.txt", "w");
if (pf != NULL)
{
//写文件
fprintf(pf, "你的姓名:%s\n你的年龄:%d\n你的身高:%.2lf\n", yyds.a, yyds.b, yyds.c);
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
fscanf 格式化输入函数
struct hunter
{
char a[20];
int b;
double c;
};
int main()
{
struct hunter yyds = { 0 };
FILE* pf = fopen("file.txt", "r");
if (pf != NULL)
{
//读文件
fscanf(pf, "%s%d%.2lf", &(yyds.a), &(yyds.b), &(yyds.c));
printf("%s %d %.2lf", yyds.a, yyds.b, yyds.c);
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
fread 和 fwrite
fwrite 二进制输出
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
FILE* pf = fopen("file.txt", "wb");
if (pf != NULL)
{
//二进制写文件
fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
注:如果各位想进一步看清的话:
fread 二进制输入
int main()
{
int arr[10] = { 0 };
FILE* pf = fopen("file.txt", "rb");
if (pf != NULL)
{
//读文件
fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
文件的随机读写
fseek
offset:
- 二进制文件:要从原点偏移的字节数。
- 文本文件:要么为零,要么为ftell返回的值。
origin:
Constant | Reference position |
SEEK_SET | 文件开始 |
SEEK_CUR | 文件指针的当前位置 |
SEEK_END | 文件结束 |
int main()
{
FILE* pf = fopen("file.txt", "w");
if (pf != NULL)
{
fputs("hunter yyds", pf);
fseek(pf, 7, SEEK_SET);
fputs("NB", pf);
//文件关闭
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
ftell
看光标所处位置。
int main()
{
FILE* pf = fopen("file.txt", "r");
if (pf != NULL)
{
int ch = fgetc(pf);
printf("%c\n", ch);//h
ch = fgetc(pf);
printf("%c\n", ch);//u
ch = fgetc(pf);
printf("%c\n", ch);//n
ch = fgetc(pf);
printf("%c\n", ch);//t
int pos = ftell(pf);
printf("pos = %d\n", pos);
//文件关闭
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
rewind
回到起始位置。
int main()
{
FILE* pf = fopen("file.txt", "r");
if (pf != NULL)
{
int ch = fgetc(pf);
printf("%c\n", ch);//h
ch = fgetc(pf);
printf("%c\n", ch);//u
ch = fgetc(pf);
printf("%c\n", ch);//n
ch = fgetc(pf);
printf("%c\n", ch);//t
int pos = ftell(pf);
printf("pos = %d\n", pos);
rewind(pf);
pos = ftell(pf);
printf("pos = %d\n", pos);
//文件关闭
fclose(pf);
pf = NULL;//防止野指针
}
return 0;
}
后语
希望各位在翻阅过本篇文章各位能够对 C 语言文件操作有更加深刻的印象。
希望能对各位有所帮助,如果各位有任何疑问,欢迎各位留言,我们可以进行友好的探讨与交流。
欢乐的时间总是过得特别快。又到时间讲bye,我们下一篇再见!!!