目录
1.什么是文件
2.文件名
?3.文件分类
4.文件缓冲区
??5.文件类型指针
?6.打开文件
? 7.关闭文件
8.顺序读写
fputc---将字符写入文件
fgetc---读取文件内的字符
fputs---向文件写入字符串
? fgets---读取文件字符串
fprintf---格式化数据输入文件
??fscanf---格式化读取文件信息
?fwrite--按照二进制形式写入文件
9 流
10.sscanf和sprintf
11.随机读写
rewind函数---文件指针指向开头
fseek函数---改变文件指针位置
ftell---返回文件指针相对于起始位置的偏移量
12.文件读写的出错检测
1.ferror函数---检查输入输出函数错误
2.feof函数---检测流上的文件结束符
3.clearerr函数---清除文件结束符
1.什么是文件
文件有不同的类型,在程序设计中,主要分为程序文件和数据文件。
程序文件:包括有源程序文件(后缀.c),目标文件(后缀.obj),可执行文件(.exe)
数据文件:文件的内容不是程序,而是程序运行时写入的数据。
我们所讨论的就是数据文件。
我们之前的代码,都是直接输入输出数据,程序结束后数据不会保留,使用文件操作,可以将数据写入磁盘中保存起来。
2.文件名
一个文件有且只有一个文件名,文件标识包括有三部分:文件路径,文件名主干,文件后缀
?3.文件分类
数据文件可以分为二进制文件和ASCII文件(文本文件)。
二进制文件:数据在内存中是以二进制的形式存放的,如果说不加转化的输出到了外存,就是二进制文件。
文本文件:数据在内存中是以二进制的形式存放的,如果说加以转化的输出到了外存,以ASCII码的形式展现,就是文本文件。
?10000在内存中以16进制表示为10 27 00 00,使用二进制形式时,对这个二进制文件使用二进制编译器编译,得到的二进制码是10 27 00 00。
也就是说,使用二进制输入数据时,把内存的内容原封不动的存储到了磁盘中,减少了使用文本文件时二进制形式和ASCII形式的相互转化,故而二进制的形式在程序中比较节约时间。
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "w+");
if (pf == NULL)
{
perror("error");
return -1;
}
int a = 10000;
fwrite(&a, 4, 1, pf);
return 0;
}
4.文件缓冲区
文件缓冲区就是系统自动的在内存里为程序每一个使用的文件都分配一个文件缓冲区。向磁盘里输入数据,先将数据输入到文件缓冲区,装满了文件缓冲区之后,将里面的数据一起分配到磁盘中去。读取磁盘数据类似。缓冲区大小由c编译系统来确定。
这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
?5.文件类型指针
我们在打开文件的时候,程序会自己创建一个文件信息区,这个文件信息区是结构体类型的,里面存放着文件的各种信息,结构体的名称是FILE。
声明FILE结构体的信息在头文件stdio.h中,可以直接使用FILE定义变量。
例如FILE *p,p是指向FILE类型的指针变量。p指向了文件信息区,通过p可以访问文件信息区的信息,通过文件信息区的信息就可以找到匹配的文件。也就是说,通过文件指针变量就可以找到和它相关联的文件。
?6.打开文件
格式:fopen(文件名,使用文件方式)
fopen函数
函数原型:FILE *fopen(const char *filename, const char *mode);
函数功能:使用给定的模式mode打开filename所指向的文件。
返回值:文件顺利打开后,返回指向文件的文件指针。如果文件打开失败则返回 NULL,并把错误代码存在error中。
方式 | ? 说明 | r | 以只读方式打开文件,该文件必须存在。 | r+ | 以读/写方式打开文件,该文件必须存在。 | rb+ | 以读/写方式打开一个二进制文件,只允许读/写数据。 | rt+ | 以读/写方式打开一个文本文件,允许读和写。 | w | 打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。 | w+ | 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。 | a | 以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留. | a+ | 以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留. | wb | 以只写方式打开或新建一个二进制文件,只允许写数据。 | wb+ | 以读/写方式打开或新建一个二进制文件,允许读和写。 | wt+ | 以读/写方式打开或新建一个文本文件,允许读和写。 | at+ | 以读/写方式打开一个文本文件,允许读或在文本末追加数据。 | ab+ | 以读/写方式打开一个二进制文件,允许读或在文件末追加数据。 |
? 7.关闭文件
fclose函数
函数原型:int fclose( FILE *fp );
函数功能:关闭文件
返回值:关闭成功,返回0,关闭失败,返回-1
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("text.txt", "r");//相对路径,在当前程序下查找
//FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r");//绝对路径,\转义,改为\\
//FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "w");
//在text文件不存在时,桌面会新建一个text.txt的文件 在text文件存在时,文件里面的内容将被清零
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
fclose(pf);
pf = NULL;
return 0;
}
8.顺序读写
顺序读写:文件读写的顺序和文件中的物理顺序一致。
程序中的数据放在内存中,将数据写到文件中叫做输出,文件里的信息读取到内存,称为输入。
输入输出是针对内存来说的,文件存储在硬盘里,数据存储在内存里,将数据写入到文件,是将内存里的数据写入硬盘,对内存而言是输出。文件信息写入内存,对内存而言是输入。
fputc---将字符写入文件
函数功能:将字符写入文件
函数原型:?int fputc(int char, FILE *stream)?把参数?char?指定的字符(一个无符号字符)写入到指定的流 stream (所有流)中,并把位置标识符移动。
返回值:函数返回写入文件的字符的ASCII码值,出错时,返回-1。成功写入时,文件内的指针会后移一个字节。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "w+");
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
char ch = getchar();
while (ch != '\n')
{
fputc(ch, pf);//输入一个字符,内部指针后移,否则第二个字符会覆盖第一个字符
ch = getchar();
}
fclose(pf);
pf = NULL;
return 0;
}
fgetc---读取文件内的字符
函数功能:将文件内的数据读入内存。读取一个字节后,内部指针位置后移一个字节。
函数原型:int fgetc(FILE *s);
返回值:得到字符的ASCII码值,出错时,返回-1。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r");
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
int ch = fgetc(pf);
printf("%c", ch);
ch = fgetc(pf);
printf("%c", ch);
fclose(pf);
pf = NULL;
return 0;
}
fputs---向文件写入字符串
函数原型:int fputs(const char *str, FILE *stream);
返回值:该函数返回一个非负值,如果发生错误则返回 EOF(-1)。
函数功能:向指定的文件写入一个字符串(不自动写入字符串结束标记符‘\0’)。成功写入一个字符串后,文件的位置指针会自动后移。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r+");
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
fputs("hello \n", pf);
fputs("hello", pf);
fclose(pf);
pf = NULL;
return 0;
}
? fgets---读取文件字符串
函数原型: char *fgets(char *str, int n, FILE *stream);
-
str-- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。 -
n-- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。 -
stream-- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。
返回值:成功,返回str的地址,失败,返回NULL
函数功能:从指定的流 stream 读取一行,并把它存储在str所指向的字符串内。当读取n-1个字符时,在第n个位置补\0,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r+");
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
char arr[20];
fgets(arr, 5, pf);
fclose(pf);
pf = NULL;
return 0;
}
fprintf---格式化数据输入文件
函数功能:将数据按照不同格式输入到文件里。
调用方式:fprintf(文件指针,格式字符串,输出表列)
#include<stdio.h>
#include<string.h>
#include<errno.h>
struct s
{
int a;
float b;
};
int main()
{
struct s s = { 122,7.98f };
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r+");
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
fprintf(pf, "%s\n", "ho");
fprintf(pf, "%d %.2lf\n", s.a, s.b);
fprintf(pf, "%c\n", 'h');
fclose(pf);
pf = NULL;
return 0;
}
??fscanf---格式化读取文件信息
函数功能:格式化读取文件信息
函数调用:fscanf(文件指针,格式字符串,输入表列)
返回值:整型,成功返回读入的参数的个数,失败返回-1
#include<stdio.h>
#include<string.h>
#include<errno.h>
struct S
{
int a;
float b;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r+");
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
char arr[20] = { 0 };
fscanf(pf,"%s", arr);
fscanf(pf,"%d%f", &(s.a), &(s.b));
printf("%s ", arr);
printf("%d %.2f", s.a, s.b);
fclose(pf);
pf = NULL;
return 0;
}
?fwrite--按照二进制形式写入文件
函数原型:size_t fwrite(const void *ptr, size_t size, size_t? n, FILE*stream)
-
ptr-- 这是指向要被写入的元素数组的指针。 -
size-- 这是要被写入的每个元素的大小,以字节为单位。 -
n-- 这是元素的个数,每个元素的大小为 size 字节。 -
stream-- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
函数功能:把ptr所指向的数组中的数据写入到给定流stream中。
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "wb+");
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
int a[2] = {1,2}
fwrite(&a, sizeof(arr[0]), 2, pf);
fclose(pf);
pf = NULL;
return 0;
}
fread---按照二进制形式读取
返回值:返回成功读取的对象个数,若出现错误或到达文件末尾,则可能小于count。若size或count为零,则fread返回零且不进行其他动作。
int main()
{
struct S s = { 0 };
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "rb");
if (pf == NULL)
{
printf("%s", strerror(errno));
return -1;
}
int a[2] = { 0 };
fread(&a, 4, 2, pf);
printf("%d", a[0]);
fclose(pf);
pf = NULL;
return 0;
}
9 流
输入输出是数据传送过程,数据像流水一样从某一处传递到另外一处,我们形象的将数据的传递过程称之为流,也就是数据流。
?
#include<stdio.h>
int main()
{
fputc('8', stdout);//stdout,stdin,stderr也是FILE*类型的,将字符输出到屏幕
//fpuc适用于所有输出流
fputc('y', stdout);
return 0;
}
10.sscanf和sprintf
sprintf---将格式化数据写入字符串中
sprintf(目标字符串,格式字符串,数据表列)
sscanf---读取格式化的字符串中的数据
调用格式:sscanf(目标字符串,格式字符串,数据表列)
struct S
{
int a;
float b;
char name[20];
};
#include<stdio.h>
int main()
{
struct S s = { 120,3.14f,"hello" };
struct S a;
char arr[100] = { 0 };
sprintf(arr, " % d % .2lf % s ", s.a, s.b, s.name);
printf("%s",arr);
sscanf(arr, "%d %f %s", &(a.a), &(a.b), a.name);
printf("%d %.2lf %s ", a.a, a.b, a.name);
return 0;
}
11.随机读写
rewind函数---文件指针指向开头
函数原型:void rewind(FILE *stream)?
函数功能:设置文件位置为给定流?stream?的文件的开头。
返回值:无
fseek函数---改变文件指针位置
调用格式:fseek(文件类型指针,位移量(long型),起始点)
文件开始位置:用数字0替代
文件当前位置:用数字1替代
文件末尾位置:用数字2替代
ftell---返回文件指针相对于起始位置的偏移量
函数原型:long int ftell(FILE *stream)?返回给定流 stream 的当前文件位置。
返回值:出错返回-1L
#include<stdio.h>
int main()
{//abcdefghij
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r");
if (pf == NULL)
{
perror("error");
return -1;
}
fseek(pf, -3, 2);//指针指向了文件末尾偏移量为-3的地址,也就是指向了h
int ch = fgetc(pf);//fgetc函数执行之后,指针偏移至i
printf("%c", ch);
fseek(pf, -1, 1);//指针指向了当前指针向前一个字节,也就是指向了h
ch = fgetc(pf);
printf("%c", ch);
fseek(pf, 2, 0);//指针指向了文件开头偏移量为2的地址,也就是指向了c
ch = fgetc(pf);
printf("%c", ch);
rewind(pf);//指针回到开头 指向a
ch = fgetc(pf);
printf("%c", ch);
int ret = ftell(pf);//计算相对于文件开头的偏移量
if (ret != -1L)
printf("%d ", ret);
fclose(pf);
pf = NULL;
return 0;
}
12.文件读写的出错检测
fgetc---出错,返回-1
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r");
if (pf == NULL)
{
perror("error");
return -1;
}
int ch = 0;
while(ch != -1)
{
ch = fgetc(pf);
printf("%c ", ch);
}
fclose(pf);
pf = NULL;
return 0;
}
fgets---出错,返回NULL
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "r");
if (pf == NULL)
{
perror("error");
return -1;
}
char arr[20];
while (fgets(arr, 3, pf) != NULL)
{
printf("%s ", arr);
}
fclose(pf);
pf = NULL;
return 0;
}
fread---出错时返回值<参数count
#include<stdio.h>
int main()
{//文件数据二进制的 1 2 3 4 5 6 7
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "rb +");
if (pf == NULL)
{
perror("error");
return -1;
}
int c[8] = { 0 };
int i = 0;
int ret = fread(&(c[i]), 4, 1, pf);
while ( ret==1 &&i<=7)
{
i++;
ret = fread(&(c[i]), 4, 1, pf);
}
for ( i = 0; i < 7; i++)
printf("%d ", c[i]);
fclose(pf);
pf = NULL;
return 0;
}
fscanf---失败返回EOF(-1)。
struct s
{
int a;
char name[10];
};
#include<stdio.h>
int main()
{
struct s s= { 10,"zhangsan" };
struct s m = { 20,"liming" };
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "rb");
if (pf == NULL)
{
perror("error");
return -1;
}
while (fscanf(pf, "%d %s", &(s.a), s.name) != -1)
{
printf("%d %s", s.a, s.name);
}
fclose(pf);
pf = NULL;
return 0;
}
1.ferror函数---检查输入输出函数错误
在调用各种输入输出函数(如 putc.getc.fread.fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。?
调用格式 ferror(文件指针)
返回值:成功,返回0,错误返回非0值
每使用一次输入输出函数,都会产生一个新的ferror的返回值,应当在调用一个输入输出函数后立即检查ferror函数的值。
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "w");
if (pf == NULL)
{
perror("error");
return -1;
}
char arr[20] = "qwert";
fwrite(arr, 1, 5, pf);
if (ferror(pf))
printf("出错");
else
printf("写入文件成功");
fclose(pf);
pf = NULL;
return 0;
}
2.feof函数---检测流上的文件结束符
feof判断读取文件内容时的结束原因,是文件读取错误还是到了文件末尾
函数原型:int feof(FILE *stream);
返回值:文件结束:返回非0值,文件没结束,返回0
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\30283\\Desktop\\text.txt", "rb");
if (pf == NULL)
{
perror("error");
return -1;
}
char arr[20] = { 0 };
fread(arr, 1, 4, pf);
if (ferror(pf))
printf("出错");
if (feof(pf))
printf("文件遇到末尾");
fclose(pf);
pf = NULL;
return 0;
}
3.clearerr函数---清除文件结束符
函数原型:void clearerr(FILE *stream)?
函数功能:清除给定流 stream 的文件结束和错误标识符。
假设ferror函数结果为非0值,也就是出现了输入输出错误,使用clearerr函数将值置为0,从而进行之后的判断,否则这个结果会一直被保留。
#include <stdio.h>
int main()
{
FILE *fp;
char c;
fp = fopen("file.txt", "w");
c = fgetc(fp);
if( ferror(fp) )
{
printf("读取文件:file.txt 时发生错误\n");
}
clearerr(fp);
if( ferror(fp) )
{
printf("读取文件:file.txt 时发生错误\n");
}
fclose(fp);
return(0);
}
|