青岛网站建设多少钱,163免费邮箱注册,建设网站的目标客户群,松江泖港网站建设目录1.文件指针2.文件的打开和关闭3.文件的读写3.1文件的顺序读写fgetc和fputcfgets和fputsfscanf和fprintffread和fwrite3.2文件的随机读写fseekftellrewind4.文本文件和二进制文件5.文件读取结束的判定6.文件缓冲区1.文件指针
在文件操作中#xff0c;一个关键的概念是文件…
目录1.文件指针2.文件的打开和关闭3.文件的读写3.1文件的顺序读写fgetc和fputcfgets和fputsfscanf和fprintffread和fwrite3.2文件的随机读写fseekftellrewind4.文本文件和二进制文件5.文件读取结束的判定6.文件缓冲区1.文件指针
在文件操作中一个关键的概念是文件类型指针简称文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区用来存放文件的相关信息如文件的名字文件状态及文件当前的位置等。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的取名FILE
这个FILE结构体在不同的编译器中的成员内容不完全相同但大同小异。
每当打开一个文件的时候系统会根据文件的情况自动创建一个FILE结构的变量并填充其中的信息使用者不必关心细节。 一般都是通过一个FILE的指针来维护这个FILE结构的变量这样使用起来更加方便。
下面创建一个FILE*的指针变量
FILE* pf;2.文件的打开和关闭
文件在读写之前应该先打开文件在使用结束后需要关闭文件
用fopen函数打开文件
FILE * fopen ( const char * filename, const char * mode );filename是要打开文件的文件名mode是文件的打开方式如果打开文件成功会返回一个FILE*的指针变量指向该文件也相当于建立了指针和文件的关系如果打开失败会返回一个NULL指针所以在打开一个文件后需要检查是否打开成功
mode打开方式如下
文件使用方式含义如果指定文件不存在“r”只读为了输入数据打开一个已经存在的文本文件出错“w”只写为了输出数据打开一个文本文件建立一个新的文件“a”追加向文本文件尾添加数据建立一个新的文件“rb”只读为了输入数据打开一个二进制文件出错“wb”只写为了输出数据打开一个二进制文件建立一个新的文件“ab”追加向一个二进制文件尾添加数据出错“r”读写为了读和写打开一个文本文件出错“w”读写为了读和写建议一个新的文件建立一个新的文件“a”读写打开一个文件在文件尾进行读写建立一个新的文件“rb”读写为了读和写打开一个二进制文件出错“wb”读写为了读和写新建一个新的二进制文件建立一个新的文件“ab”读写打开一个二进制文件在文件尾进行读和写建立一个新的文件
打开一个文件后还需将这个文件关闭用到fclose函数
下面我们打开一个文件,并且使用后将其关闭
int main()
{//打开文件FILE* pf fopen(test.txt, w);if (pf NULL){perror(fopen);return 1;}//关闭文件fclose(pf);pf NULL;//最后要把文件指针赋为空return 0;
}3.文件的读写
首先我们需要明白什么是输出输入
在前面的内容中我们习惯把printf叫做输出函数把scanf叫做输入函数 其实所谓的输入输出是对于程序(内存)而言
把内存中的数据取出来让数据在屏幕上显示出来这就是输出/写因为把数据从内存中取出来把从键盘获得的数据存到内存中这就叫输入/读 现在有了文件这个概念也就是内存与文件中有一种输入输出关系我们将内存中的数据取出放到文件中就叫做输出/写将数据的来源从键盘换做文件从文件中获得数据放到内存中就叫做输入/读
这里要好好理解输入输出便于学习下面的读写操作 3.1文件的顺序读写
fgetc和fputc
fputc是字符输出函数,适用于所有输入流
int fputc ( int character, FILE * stream );character是要输出的字符是int类型的原因是字符以ASCII码的形式存储stream 是指向标识输出流的FILE指针如果输出成功返回所写字符的ASCII值如果输出失败返回EOF
下面我们向test.txt中写几个字符
int main()
{//打开文件FILE* pf fopen(test.txt, w);if (pf NULL){perror(fopen);return 1;}//写文件fputc(a, pf);fputc(b, pf);fputc(c, pf);fputc(d, pf);//关闭文件fclose(pf);pf NULL;return 0;
}打开test.txt文件可以看见写文件成功 这里注意因为以w方式打开文件所以在每次写入文件都是从头开始写也就是会覆盖上次写入的内容如果想接着上次的内容写就需要以a方式打开文件 fgets是字符输入函数,适用于所有输入流
int fgetc ( FILE * stream );如果读文件成功会返回读到字符的ASCII值如果失败返回EOF在FILE中有一个定位文件读取位置的一个指针当调用fgetc后这个定位指针会向后挪动指向下一个字符所以如果文件中有许多字符多次调用fgetc函数即可
下面我们读取test.txt文件
int main()
{//打开文件FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}//读文件int ret fgetc(pf);printf(%c, ret);ret fgetc(pf);printf(%c, ret);ret fgetc(pf);printf(%c, ret);ret fgetc(pf);printf(%c, ret);//关闭文件fclose(pf);pf NULL;return 0;
}成功读取 fgets和fputs
fputs是文本行输出函数适用于所有输入流
int fputs ( const char * str, FILE * stream );str是要写入文件的字符串如果写入文件成功返回一个非负值如果失败返回EOF每写入一个字符串不会换行如果想换行就要写入\n
下面写入2个字符串
int main()
{//打开文件FILE* pf fopen(test.txt, w);if (pf NULL){perror(fopen);return 1;}//写入文件fputs(hello!\n, pf);fputs(你好!\n,pf);//关闭文件fclose(pf);pf NULL;return 0;
}写入成功 fgets是文本行输入函数适用于所有输入流
char * fgets ( char * str, int num, FILE * stream );将读到的字符串放到指针str指向的空间中num是读取的字符数(包括\0)传参num个其实会读取文件中num-1个字符最后一个位置放\0fgets只处理一行字符串如果读的数大于某一行的长度也不会去读下一行的字符串fgets每处理一次FILE中的定位指针会向后挪动指向下一个位置如果函数操作成功返回str失败返回NULL
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);fgets(arr, 5, pf);printf(%s\n, arr);//关闭文件fclose(pf);pf NULL;return 0;
}fscanf和fprintf
fprintf是格式化输出函数 ,适用于所有输入流
int fprintf ( FILE * stream, const char * format, ... );这个函数我们可以与printf函数对比只是参数多了一个FILE指针,其他都相同 我们可以按照我们自己规定的格式去写入文件
下面我们用一下fprintf函数
struct A
{char name[20];int age;float score;
};
int main()
{//打开文件FILE* pf fopen(test.txt, w);if (pf NULL){perror(fopen);return 1;}struct A a { jack,18,100.0 };fprintf(pf, %s %d %f, a.name, a.age, a.score);//关闭文件fclose(pf);pf NULL;return 0;
} test.txt文件 可以看到文件中的格式的确是我们规定的格式。 fscanf是格式化输入函数,适用于所有输入流
int fscanf ( FILE * stream, const char * format, ... );这个函数我们可以与scanf函数对比只是参数多了一个FILE指针
int main()
{//打开文件FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}struct A a {0};fscanf(pf, %s %d %f, a.name, (a.age), (a.score));printf(%s %d %f, a.name, a.age, a.score);//关闭文件fclose(pf);pf NULL;return 0;
}成功读取 fread和fwrite
fwrite是二进制输出函数只适用于文件流
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );指针ptr是要写入文件内容的地址因为不确定是什么数据的类型所以是void*类型size是一个写入的每个元素的大小单位是字节counrt是写入元素的个数如果写入成功返回写入元素总数一般情况下这个成功的返回值与count相等如果返回值与count不相等就说明在写入的过程中有错误如果size或count为0则返回值为0
int main()
{struct A a { jack,18,100.0 };//打开文件FILE* pf fopen(test.txt, wb);if (pf NULL){perror(fopen);return 1;}//写入文件fwrite(a, sizeof(struct A), 1, pf);//关闭文件fclose(pf);pf NULL;return 0;
}因为是二进制文件所以在文件中的内容我们看不懂但是机器可以读懂 fread是二进制输入函数只适用于文件流
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );将读取到的数据ptr指向的空间中size是读取每个元素的大小单位是字节 counrt是读取元素的个数如果成功返回值为读取到元素的个数一般情况下这个成功的返回值与count相等如果返回值与count不相等就说明读取时发生读取错误或到达文件末尾如果size或 counrt为零则该函数返回零并且流状态和 ptr 指向的内容保持不变
int main()
{struct A a { 0 };//打开文件FILE* pf fopen(test.txt, rb);if (pf NULL){perror(fopen);return 1;}//读文件fread(a, sizeof(struct A), 1, pf);printf(%s %d %f, a.name, a.age, a.score);//关闭文件fclose(pf);pf NULL;return 0;
}成功读文件 3.2文件的随机读写
fseek 根据文件指针的位置和偏移量来定位文件指针 int fseek ( FILE * stream, long int offset, int origin );offset是从origin偏移的字节数origin是用作offset参考的位置
origin的值
常量参考位置SEEK_SET文件开头SEEK_CUR文件当前位置SEEK_END文件结尾
首先我们在文件中存储abcdef 我们先用fgetc取出三个字符
int main()
{FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}int ch fgetc(pf);printf(%c\n, ch);ch fgetc(pf);printf(%c\n, ch);ch fgetc(pf);printf(%c\n, ch);fseek(pf, 2, SEEK_CUR);ch fgetc(pf);printf(%c\n, ch);}由前面知识点可知每使用一次fgetc函数那个“定位”指针就会往后挪动位此时定位指针应该指向字符d如果再使用fgetc就会得到字符d 这时使用fseek函数调整指针位置
fseek(pf, 2, SEEK_CUR);这句代码的意思是根据SEEK_CUR位置向后挪动2位这时再调用fgetc就会取出字符f
int main()
{FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}int ch fgetc(pf);printf(%c\n, ch);ch fgetc(pf);printf(%c\n, ch);ch fgetc(pf);printf(%c\n, ch);fseek(pf, 2, SEEK_CUR);ch fgetc(pf);printf(%c\n, ch);}这个函数的参数offset也可以是负数就表示根据orgin位置向前移动定位指针 ftell
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );程序中使用了3次fgetc函数文件指针向后移动3次所以再用ftell返回的偏移量就是3
int main()
{FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}int ch fgetc(pf);printf(%c\n, ch);ch fgetc(pf);printf(%c\n, ch);ch fgetc(pf);printf(%c\n, ch);//fseek(pf, 2, SEEK_CUR);int num ftell(pf);printf(%d\n, num);}rewind 让文件指针的位置回到文件的起始位置 void rewind ( FILE * stream );程序中使用了3次fgetc函数文件指针向后移动3次再使用rewind函数将指针回到起始位置所以再fgetc就得到第一个字符a
int main()
{FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}int ch fgetc(pf);printf(%c\n, ch);ch fgetc(pf);printf(%c\n, ch);ch fgetc(pf);printf(%c\n, ch);//fseek(pf, 2, SEEK_CUR);//int num ftell(pf);
// ch fgetc(pf);rewind(pf);ch fgetc(pf);printf(%c\n, ch);}4.文本文件和二进制文件
根据数据的类型数据文件可以分为两种文本文件和二进制文件
数据在内存中以二进制的形式存储如果不加转换的存储到文件中就是二进制文件
如果要求在文件中以ASCII码的形式存储则需要在存储前爪转换以ASCII字符的形式存储的文件就是文本文件。
字符一律以ASCII形式存储
数值型数据既可以使用二进制形式也可以是ASCII码形式存储
下面以10000为例 10000的二进制 所以10000的二进制形式存储就是这样 如果把10000以ASCII形式存储先把10000看作字符1和四个字符0组成的一个字符串1的ASCII码值为4949的二进制为001100010的ASCII码值为4848二进制为00110000 5.文件读取结束的判定
文本文件判断是否读取结束 1.fgetc判断返回值是否为EOF 2.fgets判断返回值是否为NULL
二进制文件判断是否读取结束 fread判断返回值是否小于实际要读的个数
C语言stdio.h还有2个函数判断文件读取结束的原因
feof函数和ferror函数
feof若返回值为真就说明文件正常读写遇到文件结束标志而结束的ferror,若返回值为真就说明文件在读取过程中出错而结束
判断文本文件读取结束原因的例子 int main()
{int c 0;FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}while ((c fgetc(pf)) ! EOF){putchar(c);}if (ferror(pf)){printf(I/O error when reading\n);}else if (feof(pf)){printf(End of file reached successfully\n);}fclose(pf);pf NULL;return 0;
}判断二进制文件读取结束原因的例子
enum
{SIZE 1
};
int main()
{FILE* pf fopen(test.txt, rb);if (pf NULL){perror(fopen);return 1;}int ret 0;int code 0;code fread(ret, sizeof(char),SIZE , pf);if (code SIZE){printf(Array read successfully\n);}else{if (ferror(pf))printf(Error reading\n);else if(feof(pf)){printf(End of file reached successfully\n);}}
}6.文件缓冲区 ANSIC 标准采用缓冲文件系统处理的数据文件的所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块文件缓冲区 从内存向磁盘输出数据会先送到内存中的缓冲区装 满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据则从磁盘文件中读取数据输入到内存缓 冲区充满缓冲区然后再从缓冲区逐个地将数据送到程序数据区 以输出(写文件)为例 内存中的数据不是直接就存到文件中的数据需要先存放到一个叫做输出缓冲区的空间。
想要让输出缓冲区中的数据再存放到文件中有2种情况 1.缓冲区满了 2.主动刷新缓冲区
想主动刷新缓冲区要使用fflush函数 并且fclose函数在关闭文件时也会刷新缓冲区
所以要记住 因为有缓冲区的存在C语言在操作文件的时候需要做刷新缓冲区或者在文件操作结束的时候关闭文件。 如果不做可能导致读写文件的问题。