文件操作
文件
在程序设计中,我们一般把文件分为:程序文件,数据文件(从文件的功能上划分)
程序文件
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
数据文件
数据文件是电脑系统上最常见的文件类型,一般由应用程序本身创建。大部分数据文件以二进制格式存储,小部分采用纯文本格式存储。
文件名
一个文件要有一个绝对标识,方便用户用来识别和使用
文件名主要分为三个部分:文件路径,文件名主干,文件后缀
绝对路径:
列如:c:\code\test.txt
相对路径:
如果要打开的文件在同一个文件中,可以使用相对路径:“text.txt”
列:
文件的打开和关闭
文件指针
缓冲文件系统中,关键的概念是"文件类型指针",简称“文件指针”。
每个文件在被使用时,都会在内存中开辟一个相应的文件信息区,用来存放该文件的相关信息(文件的名字,文件状态及文件的当前状态等)。
这些信息被保存在一个结构体变量中。
该类型结构体是由系统声明的,取名FILE。
列如,在VS2022编译环境提供的stdio.h头文件中有相关的声明:
此时结构体内的指针指向保存文件信息的成员
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息 ,使用者不必关心细节。
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
下面我们可以创建一个FILE*的指针变量:
FILE* pf
//定义一个文件指针 pf
这样我们就创建出了一个文件指针,接下来就可以使用这个文件指针指向文件信息区,并通过该文件信息区所保存的信息来访问本地硬盘内的文件了。
这样我们就可以使用文件指针找到其相关的文件。
文件的打开
文件在读写之前要先打开文件,在使用结束后关闭文件。
在编写程序的时候,打开文件时会返回一个FILE类型的指针变量来指向这个文件,这样就建立了指针与文件的关系。
ANSIC 中规定使用 fopen函数来打开文件,fclose函数来关闭文件
fopen 函数的使用:
FILE *fopen( const char *filename, const char *mode );
- 其中“ const char* filename ”指文件名(是字符串,文件名即文件标识符)
- 其中”const char *mode “指文件打开方式
- 返回值:若成功,返回一个文件指针,若文件打开失败,则返回一个空指针
fclose 函数的使用:
fopen(FILE* strname);
- 参数 FILE *stream : 这是指向 FILE 对象的指针,该 FILE 对象指定了要被关闭的流;
- 返回值:若文件关闭成功,则返回0;
若文件关闭失败,则返回EOF;
文件的打开方式:
文件的顺序读写
字符的输出函数:fputc
- 描述 :把参数 c 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动;
- 参数 int c :这是要被写入的字符。该字符以其ASCII 值进行传递;
- 参数 FILE *stream : 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流;
- 返回值:该函数以无符号 char 强制转换为 int 的形式(即字符的ASCII值)返回写入的字符,如果发生错误则返回 EOF
输入26个字母
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
for (int a = 'a'; a <= 'z'; a++)
{
fputc(a, pf);
}
fclose(pf);
pf = NULL;
return 0;
}
运行结果:
字符的输入函数:fgetc
- 参数 FILE *stream :这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流;
- 返回值:该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
/*for (int a = 'a'; a <= 'z'; a++)
{
fputc(a, pf);
}*/
for (int i = 0; i < 26; i++)
{
int ch = fgetc(pf);
printf("%c ", ch);
}
fclose(pf);
pf = NULL;
return 0;
}
注意:
- fgetc 函数对字符的读取,每读取一个字符,该函数的指针会自动向后移一位
文本行的输出函数:fputs
- 参数 const char *str : 这是一个字符串,有’\0’结尾。
- 参数 FILE *stream : 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流;
- 返回值:该函数返回一个非负值,如果发生错误则返回 EOF
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("hello world", pf);
fclose(pf);
pf = NULL;
return 0;
}
文本行输入函数:fgets
- 描述: 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。
- 参数 char *str :这是指向一个指针,该指针指向了要读取的字符串;
- 参数 int n : 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度;
- 参数 FILE *stream :这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流;
- 返回值:如果成功,该函数返回相同的 str 参数;如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针;如果发生错误,返回一个空指针;
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//fputs("hello world", pf);
char a[27] = { 0 };
fgets(a,26 ,pf);
printf("%s", a);
fclose(pf);
pf = NULL;
return 0;
}
格式化输出函数:fprintf
该函数和 printf差不多,只是多了一个指向文件的指针,这里的意思其实是将后面的数据以不同的格式写入指针指向的文件信息中。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef struct S
{
char name[20];
int age;
double b;
}S;
int main()
{
S s = { "zhang shang",18,3.14 };
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fprintf(pf, "%s %d %lf", s.name, s.age, s.b);
fclose(pf);
pf = NULL;
return 0;
}
格式化输入函数 fscanf
与 scanf一样,只是多了一个文件指针。这里的意思是将文件指向的文件消息以不同格式读出并且保存在不同类型的变量中。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef struct S
{
char name[20];
int age;
double b;
}S;
int main()
{
S s = { 0 };
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fscanf(pf, "%s %d %lf", s.name, &s.age, &s.b);
printf("%s %d %lf", s.name, s.age, s.b);
fclose(pf);
pf = NULL;
return 0;
}
二进制输出:fwrite
- 描述:把 ptr 所指向的数组中的数据写入到给定流 stream 中;
- 参数 void (*)buffer :这是指向内存块的指针;
- 参数 size_t size :这是要读取的每个元素的大小,以字节为单位;
- 参数 size_t count :这是元素的个数;
- 参数 FILE(*)stream : 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流;
- 返回值:如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef struct S
{
char name[20];
int age;
double b;
}S;
int main()
{
S s = {"zhangshang",23,3.14};
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fwrite(&s, sizeof(S), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
二进制输入:fread
- 描述:从给定流 stream 读取数据到 ptr 所指向的空间中;
- 参数 void (*)buffer :这是指向内存块的指针;
- 参数 size_t size :这是要读取的每个元素的大小,以字节为单位;
- 参数 size_t nmemb :这是元素的个数;
- 参数 FILE(*)stream : 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流;
- 返回值 :成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果返回值小于元素个数 ,则发生错误或者读到文件末尾。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef struct S
{
char name[20];
int age;
double b;
}S;
int main()
{
S s = { 0 };
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fread(&s, sizeof(S), 1, pf);
printf("%s %d %lf", s.name, s.age, s.b);
fclose(pf);
pf = NULL;
return 0;
}