fopen
在文件操作这一部分,首先要提到的就是fopen函数。
FILE* fopen(const char *filename, const char *mode);
在C语言标准中,fopen函数有两个参数,第一个参数是指向一个文件名的字符指针,实际上这个文件名存在与否都受到第二个参数的影响。第二个参数是代表打开的模式,如"r"代表只读,"w"代表只写,如果文件不存在则无法打开;如果文件名不存在,则会新建一个文件,如果文件存在,就会清空原来文件中的数据并写入新的数据;"rb"代表以二进制的方式读入数据,要求打开的文件所存储的数据也是以二进制方式存储的;"wb"代表将数据以二进制的形式写入文件,如果文件名不存在,则会新建一个文件,如果原来的文件中有数据,则会将录入的数据覆盖掉原来的数据。还有更多的打开模式所对应的字符串,这里不一一例举了。
fclose
int fclose( FILE *stream );
fclose函数有一个参数,这个参数就是在此之前由fopen所创建的文件指针。
fclose函数与fopen函数是配对的,在使用fopen函数创建了一个FILE*的文件指针后,我们将进行各种文件操作,最后在使用完文件后,需要对文件进行关闭操作并释放掉文件指针。使用文件一般有三个基本的步骤,这个基本的操作过程表述如下:
1、打开文件
2、使用文件
3、关闭文件
#include <stdlib.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
//如果打开失败,fopen会返回NULL
if (pf == NULL)
{
perror("fopen");
return 1;
}
//使用文件
//...
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
上面代码演示了使用文件指针的一般过程,注意使用fopen创建文件指针的时候,需要检查。最后使用fclose关闭文件并将pf置为NULL
fgetc
int fgetc( FILE *stream );
从一个流里获取一个字符,适用于所有输入流。
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//使用文件
//假设文件里存放的是26个小写字母,abcdef…
char arr[30] = { 0 };
int i = 0;
for (i = 0; i < 20; i++)
{
arr[i] = fgetc(pf);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fgetc从一个标准流中读取一个字符,返回其ASCII码值,所以返回值是int型的。
fputc
int fputc( int c, FILE *stream );
向一个流中输入一个字符,适用于所有输出流。
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//使用文件
//向文件里写入26个小写字母,abcdef…
int i = 0;
for (i = 'a'; i <= 'z'; i++)
{
fputc(i, pf);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fputc第一个参数是对应字符的ASCII码值,第二个参数是需要输出到的流。可以使标准输出流:屏幕,也可以是文件。
fgets
char *fgets( char *string, int n, FILE *stream );
fgets与fgetc有相似之处,fgets是读入一行,或者将fgets称为文本行输入函数。该函数有3个参数,第一个是存储字符串数据的位置,第二个参数是需要读入数据的个数,第三个参数是读取数据的源地址,是一个文件指针。
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//使用文件
//假设文件里的一行存放的是26个小写字母,abcdef…
char arr[30] = { 0 };
char *ret = fgets(arr, 26, pf);
//打印
printf("%s\n", ret);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
该函数返回存储字符串的地址。
fputs
int fputs( const char *string, FILE *stream );
fputs与fputc有相似之处,fputs是输出一行,或者将fputs称为文本行输出函数。向所有输出流输出一行字符串,包括文件、标准输出流等。第一个参数是待输出的字符串地址,第二个是输出流。
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//使用文件
//向文件里写入"abcdef"
char arr[] = "abcdef";
fputs(arr, pf);
//或者向屏幕输出"abcdef"
fputs(arr, stdout);//stdout是标准输出流
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
该函数返回值是int型,如果函数调用失败,返回EOF。
fscanf
格式化的输入函数
int fscanf( FILE *stream, const char *format [, argument ]... );
与scanf相似,具体用法如代码所示:
struct Stu
{
char name[20];
int age;
double score;
};
int main()
{
//创建一个结构体变量
struct Stu s = { 0 };
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//格式化的读入数据
//假设文件里存放的数据是:"张三" 20 95.5
fscanf(pf, "%s %d %lf", s.name, s.age, s.score);
//打印
printf("%s %d %lf\n", s.name, s.age, s.score);
return 0;
}
fscanf函数第一个参数是读取数据的文件地址,该函数适用于所有输入流,所以可以从标准输入流中读取数据,如键盘。
fprintf
int fprintf( FILE *stream, const char *format [, argument ]...);
与printf函数的使用方法相似,fprintf函数适用于所有输出流,具体使用方法如代码所示:
struct Stu
{
char name[20];
int age;
double score;
};
int main()
{
//创建一个结构体变量并赋初值
struct Stu s = {"张三", 20, 95.5};
//打开文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//格式化的写入数据
fprintf(pf, "%s %d %lf\n", s.name, s.age, s.score);
//注意,这里的换行符'\n'可以不加,加上的效果就是在文本文件里输入数据后再换行
return 0;
}
fprintf函数也可以像屏幕进行格式化的输出,只要将pf指针换为stdout即可。
sscanf
int sscanf( const char *buffer, const char *format [, argument ] ... );
sscanf函数是从一个字符串里进行格式化的读入操作,注意,这里的数据源是一个字符串。sscanf函数的具体用法如代码所示:
struct Stu
{
char name[20];
int age;
double score;
};
int main()
{
//创建一个结构体变量
struct Stu s1 = { 0 };
struct Stu s2 = { 0 };
//创建一个常量字符串
char* arr = "李四 21 92.5";
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//格式化的读入数据
//假设文件里存放的数据是字符串类型的:"张三 20 95.5"
sscanf(pf, "%s %d %lf", s1.name, s1.age, s1.score);
//从常量字符串里读入数据
sscanf(arr, " % s % d % lf", s2.name, s2.age, s2.score);
//打印
printf("%s %d %lf\n", s1.name, s1.age, s1.score);
printf("%s %d %lf\n", s2.name, s2.age, s2.score);
return 0;
}
sscanf第一个参数是存储数据的字符串地址,所以特别注意该函数需要从一个字符串中提取数据。
sprintf
int sprintf( char *buffer, const char *format [, argument] ... );
sprintf与printf有相似之处,sprintf函数是将格式化的数据写入一个字符串,换句话说就是,sprintf函数将格式化的数据转换为字符串,并写入目标地址。sprintf函数的具体用法如代码所示:
struct Stu
{
char name[20];
int age;
double score;
};
int main()
{
//创建一个结构体变量并赋初值
struct Stu s1 = { "张三", 20, 95.5 };
struct Stu s2 = { "李四", 21, 92.5 };
//创建一个字符数组
char arr[255] = { 0 };//
//打开文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//将格式化的数据写入字符串中
//写入文件
sprintf(pf, "%s %d %lf", s1.name, s1.age, s1.score);
//写入字符数组
sprintf(arr, "%s %d %lf", s2.name, s2.age, s2.score);
return 0;
}
sprintf函数是格式化的输出函数,适用于所有的输出流,类似的,可以将数据输出到屏幕上,第1个参数是stdout就可以了。
fread
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
fread是以二进制的形式从文件中读入数据,fopen的第二个参数需要是"rb"。
fread函数第一个参数是存储数据的地址;第二个参数是每个需要读入的数据的大小,单位是字节;第三个参数是一次读入几个数据;第四个参数是指向数据源的指针。fread函数的具体用法如代码所示:
struct Stu
{
char name[20];
int age;
double score;
};
int main()
{
//创建一个结构体变量
struct Stu s = { 0 };
//打开文件
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//以二进制的形式从文件中读入数据
//
//假设文件里存放的数据是:"张三" 20 95.5的二进制数据
//注意,以上数据在文本文件中以二进制的形式存储可能是这个样子的:
//zhangsan an 屯
//具体是什么样子无关紧要,我们只需要关心函数的使用方法即可
fread(&s, sizeof(struct Stu), 1, pf);
//打印
printf("%s %d %lf\n", s.name, s.age, s.score);
return 0;
}
注意我这里的使用是一次只读入一个,即第三个参数是1,而函数的返回值是实际读取到的数据个数。例如:假设第三个参数写的是10,而fread函数在文件中进行读取后,实际上只读入了5个,那么其返回值就是5
fwrite
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
fwrite是将数据以二进制的形式写入到文件,fopen的第二个参数需要是"wb"。
fwrite函数与fread函数都有4个参数,fwrite函数的第一个参数是指向数据源的指针,即待写入数据的地址;第二个参数是每个数据的大小,单位是字节;第三个参数是每次写入多少个数据;第四个参数是被写入的文件地址,即指向被写入文件的指针。fwrite函数的具体用法如代码所示:
struct Stu
{
char name[20];
int age;
double score;
};
int main()
{
//创建一个结构体变量并赋初值
struct Stu s = {"张三", 20, 95.5};
//打开文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//以二进制的形式将数据写入文件
fwrite(&s, sizeof(struct Stu), 1, pf);
return 0;
}
同样地,fwrite函数的返回值是实际读取到的数据个数。例如:假设第三个参数写的是10,而fread函数在文件中进行读取后,实际上只读入了5个,那么其返回值就是5
最后,fread和fwrite这两个函数都是只适用于文件。