文章目录
一、文件顺序读写的函数
1.1fputc函数
将字符(第一个参数)写入pf指向的文件中(pf指向文件对应的文件信息区,pf跟文件里面的内容没有关系),返回写入文件字符的ASCII值,写入失败返回EOF(-1)。
函数声明:
int fputc ( int character, FILE * stream );
使用fputc函数:
#define _CRT_SECURE_NO_WARNINGS
#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;
}
因为fputc函数适用于所有输出流,所以也可以写成(stdout替换pf):
fputc('a' + i, stdout);//stdout是标准输出流
1.2fgetc函数
从pf指向的文件中读取字符,返回读取字符的ASCII值,读取失败返回EOF(-1),读完一个字符之后会让文件指针(文件类型指针,这里指向文件里面的内容)向后走一步。
函数声明:
int fgetc ( FILE * stream );
使用fgetc函数:
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;
}
因为fgetc函数适用于所有输入流,所以也可以写成(stdin替换pf):
ch = fgetc(stdin);//stdin是标准输出流
1.3fputs函数
第一个参数是字符串的地址;写入成功返回非负值,否则返回EOF(-1)。
函数声明:
int fputs ( const char * str, FILE * stream );
使用fputs函数:
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;
}
1.4fgets函数
把读到的内容复制放到第一个参数指向的空间(第一个参数是指针);第二个参数num为放到第一个参数指向的空间的字符的个数,num为10时,实际上读到的有效个数是9个,因为最后\0也算入num中。返回第一个参数指向的空间的地址,读取失败返回NULL。
函数声明:
char * fgets ( char * str, int num, FILE * stream );
使用fgets函数:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读一行字符串
char arr[20] = {
0 };
fgets(arr, 5, pf);
printf("%s\n", arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
1.5fprintf函数(格式化输出函数)
函数声明:
int fprintf ( FILE * stream, const char * format, ... );
使用fprintf函数:
struct S
{
int n;
float f;
char arr[20];
};
int main()
{
struct S s = {
100, 3.14f, "zhangsan" };
//打开文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fprintf(pf, "%d %f %s\n", s.n, s.f, s.arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
1.6fscanf函数(格式化输入函数)
函数声明:
int fscanf ( FILE * stream, const char * format, ... );
使用fscanf函数:
struct S
{
int n;
float f;
char arr[20];
};
int main()
{
struct S s = {
0 };
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fscanf(pf, "%d %f %s", &(s.n), &(s.f), s.arr);
printf("%d %f %s\n", s.n, s.f, s.arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fgetc、fgets、fscanf适用于所有输入流,fputc、fputs、fprintf适用于所有输出流。
1.7sprintf函数(不是顺序读写函数)
函数声明:
int sprintf ( char * str, const char * format, ... );
使用sprintf函数:
struct S
{
int n;
float f;
char arr[20];
};
int main()
{
struct S s = {
200, 3.5f, "wangwu" };
//把一个结构体中的格式化数据转换成字符串
char arr[200] = {
0 };
sprintf(arr, "%d %f %s\n", s.n, s.f, s.arr);
printf("字符串的数据:%s\n", arr);
return 0;
}
1.8sscanf函数(不是顺序读写函数)
函数声明:
int sscanf ( const char * s, const char * format, ...);
使用sscanf函数:
struct S
{
int n;
float f;
char arr[20];
};
int main()
{
struct S s = {
200, 3.5f, "wangwu" };
//把一个结构体中的格式化数据转换成字符串
char arr[200] = {
0 };
sprintf(arr, "%d %f %s\n", s.n, s.f, s.arr);
printf("字符串的数据:%s\n", arr);
//把一个字符串转换成对应的格式化数据
struct S tmp = {
0 };
sscanf(arr, "%d %f %s", &(tmp.n), &(tmp.f), tmp.arr);
printf("格式化的数据:%d %f %s\n", tmp.n, tmp.f, tmp.arr);
return 0;
}
1.9三组函数的对比
scanf和printf:scanf是针对标准输入流(stdin)的格式化的输入函数。printf是针对标准输出流(stdout)的格式化的输出函数。
fscanf和fprintf:fscanf是针对所有输入流(文件流/stdin)的格式化的输入函数。fprintf是针对所有输出流(文件流/stdout)的格式化的输出函数。
sscanf和sprintf:sscanf是把字符串转换成格式化的数据的函数。sprintf是把格式化的数据转换成字符串的函数。
1.10fwrite函数(二进制输出函数)
函数声明:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
使用fwrite函数:
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = {
"zhangsan", 20, 95.5f };
FILE* pf = fopen("test.dat", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fwrite(&s, sizeof(struct S), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
1.11fread函数(二进制输入函数)
返回值为成功读到的元素的个数。
函数声明:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
使用fread函数:
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = {
0 };
FILE* pf = fopen("test.dat", "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;
}
二、文件随机读写的函数
2.1fseek函数
函数声明:
int fseek ( FILE * stream, long int offset, int origin );
根据文件指针的位置及其偏移量来定位文件指针(指向文件内容),第3个参数的选择有三种,第一种SEEK_SET(文件指针(指向文件内容)的开始位置),第二种是SEEK_CUR(文件的当前位置),第三种是SEEK_END(文件的末尾位置)。
使用fseek函数,假设文件存放的是abcdef:
int main()
{
FILE* pf = fopen("test.dat", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件,内存中存放abcdef
int ch = fgetc(pf);
printf("%c\n", ch);//读'a',然后文件指针(指向文件内容)走向下一步
ch = fgetc(pf);
printf("%c\n", ch);//读'b'
ch = fgetc(pf);
printf("%c\n", ch);//读'c'
ch = fgetc(pf);
printf("%c\n", ch);//读'd',这时文件指针指向'e'
fseek(pf, -3, SEEK_CUR);//这时文件指针指向'e'
ch = fgetc(pf);
printf("%c\n", ch);//读到'b'
fseek(pf, 1, SEEK_SET);//这时文件指针指向'a'
ch = fgetc(pf);
printf("%c\n", ch);//读到'b'
fclose(pf);
pf = NULL;
return 0;
}
2.2ftell函数
函数声明:
long int ftell ( FILE * stream );
返回文件指针相对于起始位置的偏移量。
使用ftell函数:
int main()
{
FILE* pf = fopen("test.dat", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件,内存中存放abcdef
int ch = fgetc(pf);
printf("%c\n", ch);//读'a',然后文件指针(指向文件内容)走向下一步
ch = fgetc(pf);
printf("%c\n", ch);//读'b'
ch = fgetc(pf);
printf("%c\n", ch);//读'c'
ch = fgetc(pf);
printf("%c\n", ch);//读'd',这时文件指针指向'e'
printf("%d\n", ftell(pf));
fclose(pf);
pf = NULL;
return 0;
}
2.3rewind函数
函数声明:
void rewind ( FILE * stream );
让文件指针的位置回到文件的起始位置。
使用rewind函数:
int main()
{
FILE* pf = fopen("test.dat", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件,内存中存放abcdef
int ch = fgetc(pf);
printf("%c\n", ch);//读'a',然后文件指针(指向文件内容)走向下一步
ch = fgetc(pf);
printf("%c\n", ch);//读'b'
ch = fgetc(pf);
printf("%c\n", ch);//读'c'
ch = fgetc(pf);
printf("%c\n", ch);//读'd',这时文件指针指向'e'
rewind(pf);
printf("%d\n", ftell(pf));
fclose(pf);
pf = NULL;
return 0;
}
三、文件读取结束的判断
3.1feof函数
函数声明:
int feof ( FILE * stream );
当文件读取结束的时候,feof可用来判断文件读取结束的原因是否是遇到文件尾结束。文件读取结束时,fgetc会返回EOF,fgets会返回NULL,fread返回值小于实际要读的个数。
fgetc函数返回值为EOF分析:1、遇到文件末尾返回EOF,同时设置一个遇到文件末尾了的状态,使用feof来检测这个状态。2、遇到错误返回EOF,同时设置一个遇到了错误的状态,使用ferror来检测这个状态。
使用feof函数,文本文件的例子:
int main()
{
int c = 0;
FILE* fp = fopen("test.dat", "r");//文件里保存的是abcdef
if (!fp)
{
perror("File opening failed");
return EXIT_FAILURE;//EXIT_FAILURE的定义是1
}
while ((c = fgetc(fp)) != EOF)
{
putchar(c);
}
printf("\n");
//判断读取结束的原因
if (ferror(fp))//如果ferror返回为真则走这里
{
puts("I/O error when reading");
}
else if (feof(fp))//如果feof返回为真则走这里
{
puts("End of file reached successfully");
}
fclose(fp);
fp = NULL;
return 0;
}
使用feof函数,二进制文件的例子:
enum
{
SIZE = 5
};
int main()
{
double a[SIZE] = {
1.0, 2.0, 3.0, 4.0, 5.0 };
FILE* fp = fopen("test.dat", "wb");
fwrite(a, sizeof(*a), SIZE, fp);
fclose(fp);
double b[SIZE] = {
0.0 };
fp = fopen("test.dat", "rb");
size_t ret = fread(b, sizeof(*b), SIZE, fp);
if (ret == SIZE)
{
puts("Array read successfully, contents:");
int n = 0;
for (n = 0; n < SIZE; n++)
{
printf("%lf ", b[n]);
}
putchar('\n');
}
else
{
if (feof(fp))//如果feof返回为真则走这里
{
printf("Error reading test.dat:unexpected end of file\n");
}
else if (ferror(fp))//如果ferror返回为真则走这里
{
puts("Error reading test.dat");
}
}
fclose(fp);
fp = NULL;
return 0;
}