目录
一,认识文件
1,文件名:
2,两种文件
二,文件操作
1,认识流和标准流
2,文件指针
3,文件的打开与关闭
三,文件的顺序读写
1,fputc和fgetc
2,fputs和fgets
3,fprintf和fscanf
4,fwrite和fread
四,输入流和输出流
1,所有输入流
2,所有输出流
3,格式化数据的含义
4,两组函数功能的对比
5,补充函数:sprintf和sscanf
五,文件的随机读写
1,fseek
2,ftell
3,rewind
六,文件读取结束的判定
1,判定读取结束
2,文件的拷贝
七,文件缓冲区
一,认识文件
1,文件名:
文件名分为三部分:文件路径+文件名主干+文件后缀
例如:D:/code/test.c
D:/code 就是文件路径
test就是文件主干 .c就是文件后缀(决定了文件的默认打开方式)
注意:1,文件名不能包含的字符:\ / : * ? ' < > |
2,文件名不一定包含后缀名
2,两种文件
从程序设计的角度有两种文件:程序文件、数据文件
为什么要使用文件:当我们不使用文件时,写的程序数据存储电脑的内存中,执行完后内存就释放,数据就丢失了,如果想要数据完整并永久保存,就需要使用文件。
1,程序文件
程序文件包括源程序文件(后缀为.c)、目标文件(后缀为.obj)、可执行程序(后缀为.exe)
2,数据文件
数据文件是程序进行执行时需要从中读取数据的文件,或者输出内容的文件。
其中数据文件又被分为:文本文件和二进制文件
二进制文件:数据在内存中以二进制的形式存储,不加任何形式的转化,直接存入外存的文件。
文本文件:内存中的数据经过ASCII码值转化到外存中,以ASCII字符形式存储的的文件。
数据是如何存储到文件中的?
如果是字符,就以ASCII码值的形式存储
如果是数值型的数据,则可以以ASCII码值的形式存储,也可以以二进制的形式存储
例如:有整数10000想要进行存储,则以ASCII码值存储需要5个字节,以二进制存储需要4个字节
二,文件操作
文件操作分为三步:1,打开文件 2,读写文件 3,关闭文件
在真正进行文件操作前,首先要认识流和标准流的概念
1,认识流和标准流
在执行程序时我们需要从外部设备获取数据,同时也需要输出数据到外部设备中,不同的设备的输入输出的操作方式不一样。如下图:
为了方便操作,引出了流的概念,之后我们进行数据的写入和输出,只需要操作流即可。
标准流:
C语言在启动时就会默认打开三个流:
stdin:标准输入流,通常来自键盘,文件,或其他程序的输入,scanf就是从标准流中读取数据。
stdout:标准输出流,通常输出到屏幕,文件中,printf函数就是将信息输出到标准输出流中。
stderr:标准错误流,通常输出到屏幕上。
stdin、stdout、stderr这三个流的类型都是:FILE*,称为文件指针。
C语言中,就是通过FILE*的文件指针来维护流的各种操作的
2,文件指针
每一个文件在内存中都被开辟了一个文件信息区(结构体),这个文件信息区用来存放文件的相关信息。该结构体通用起名为FILE。该结构体的地址就是文件指针,文件指针通过地址找到文件信息区,文件信息区再找到文件。
创建一个文件指针:
FILE* pf;
3,文件的打开与关闭
打开文件:
语法:FILE* fopen(const char* filename,const char* mode);
filename为打开的文件名(主干加后缀)
mode表示打开方式,有以下打开方式:
关闭文件:
语法:int fclose(FILE* stream);
stream为文件指针(流)
举例:
三,文件的顺序读写
1,fputc和fgetc
fputc函数:
核心功能:向文件中写入单个字符
语法:int putc(int c,FILE* stream);
c为要写入的字符
stream表示文件指针(流)
成功时返回写入的字符的ASCII码值
失败时返回EOF(-1)
使用案例:
fgetc函数:
核心功能:从文件中读取单个字符
语法:int fgetc(FILE* stream);
stream为文件指针(流)
成功时返回读取到的字符的ASCII码值
失败时(或读取到文件末尾)返回EOF(-1)
使用案例:
2,fputs和fgets
fputs函数:
核心功能:向文件中写入字符串
语法:int fputs(const char str,FILE* stream);
str是要输入的字符串
stream是文件指针(流)
成功时返回非负整数
失败时返回EOF(-1)
使用案例:
fgets函数:
核心功能:从文件中读取一行字符串
语法:char* fgets(char* str,int n,FILE* stream);
str为用于存储字符串的字符数组
n表示从文件中取出的字符个数,算上\0,所以实际取出n-1个字符
stream表示文件指针(流)
成功时返回指向str的指针
失败或者到文件末尾时返回NULL
使用案例:
当n-1小于字符个数时:先打印n-1个,下次循环打印剩下部分
当n-1大于字符个数时:打印完即可
3,fprintf和fscanf
1,fprintf函数
类比printf:int printf(const char* format……)
核心功能:与printf类似,不过printf是将内容输出到标准输出(一般是屏幕),而fprintf函数是将内容输出到指定的文件流或标准流当中
头文件:#include <stdio.h>
语法:int fprintf(FILE *stream,const char* format,……);
stream(文件指针 )指向已经打开的文件流
format为格式化的字符串,与printf中的内容相同
返回值:成功时返回写入的字符数,失败时返回负数
运用实例:
2,fscanf函数
类比scanf:int scanf(const char* format,……)
核心功能:与scanf类似,scanf为将格式化数据输出到标准输出流中 ,fscanf为从指定的输入流(文件流或标准流)中读取数据
头文件:#include <stdio.h>
语法:int fscanf(FILE *stream,const char* format,……);
参数含义与fprintf相同
返回值:成功时返回读取到的数据个数
读到文件末尾或发生错误时返回EOF(-1)
运用展示:
结果:张三 20 65.500000
上述是输出到文件流当中的情况
将内容输出到标准输出流当中的情况:
结果:在屏幕上打印:张三 20 65.500000
4,fwrite和fread
fwrite函数
核心功能:以二进制的形式将原始内存数据写入到文件当中,适合非文本数据(图像,音频,结构体,数组等)的写入
语法:size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
ptr:要写入的内存块的指针
size:要写入的一个数据项的大小
nmemb:要写入的数据项的数量
stream:文件指针(流),指向要被写入的文件
返回值:成功时输出成功传入的数据项的个数,如果与nmemb不相等,表示写入出错或到达文件末尾
运用实例:
fread函数
核心功能:从文件中以二进制形式读取原始内存数据,适合读取非文本数据。
语法:size_t fread(void* ptr,size_t size,size_t nmemb,FILE *stream);
参数内容含义与fwrite函数一样,不过改成从pf中读取数据到ptr当中
返回值:成功读取的数据项数量,如果返回值小于nmemb,则可能表示:
1,到达文件末尾(EOF)
2,读取错误
3,实际读取的项数不足
运用实例:
运行结果:1 2 3 4 5
四,输入流和输出流
1,所有输入流
1,标准输入流--stdin--键盘输入
函数:scanf, getchar, gets.
2,文件输入流--FILE* 打开的文件(只读r)
函数:fscanf, fgets, fgetc, fread
3,字符串输入流--从字符串中读数据
函数:sscanf
2,所有输出流
1,标准输出流--stdout 通常输出到屏幕中 ,printf就是将内容输出到标准输出流当中
2,标准错误输出--stderr 打印错误信息(通常是屏幕)
3,stdprn--不常用
3,格式化数据的含义
格式化数据:按照固定格式读写的数据
格式化就是将数据转化为人类能看懂的文本,用格式说明符控制:%d %f %c %s
非格式化:看不懂,供机器使用例如:fread,fwrite
4,两组函数功能的对比
5,补充函数:sprintf和sscanf
sprintf函数:
核心功能:把格式化数据转化成字符串传入到字符数组当中
头文件:#include <stdio.h>
语法:int sprintf(char* str,const char* format,……)
str为指向目标字符数组的指针,用于存放生成的字符串。字符指针的大小必须足够大,容纳输入的所有的内容。
format:名为格式化的字符串,与printf中的类似。
返回值:如果成功,则返回写入的字符总数(不包括结尾的\0),如果失败,则返回一个负数。
sscanf函数
核心功能:从字符串中读取格式化数据到变量中
头文件:#include <stdio.h>
语法:int sscanf(const char *str,const char format,……);
str:源字符串,从中读取数据
format:格式化字符串,与scanf中的类似。
返回值:成功读入并赋值的变量个数
一个都没有读入进去:返回0
在第一个读入前就结束:返回EOF(-1)
运用实例:
五,文件的随机读写
1,fseek
核心功能:根据文件指针的位置和偏移量改变文件指针位置
语法:int fseek(FILE *stream,long int offset,int origin);
stream表示文件指针(流)
offset表示偏移量,可正可负
origin表示起始位置,有三个取值:
1,SEEK_SET(0):从文件开头开始
2,SEEK_CUR(1):从当前位置开始
3,SEEK_END(2):从文件末尾开始
返回值:如果成功,返回0,如果失败,返回非零值
运用展示:
2,ftell
核心功能:返回文件指针相对于起始位置的偏移量
语法:long int ftell(FILE *stream);
stream表示文件指针(流)
返回值:如果成功返回相对起始位置的偏移量,失败则返回-1L(长整型的-1)
运用实例:
3,rewind
核心功能:让文件指针返回到文件的起始位置
语法:void rewind(FILE *stream);
stream为文件指针(流)
六,文件读取结束的判定
1,判定读取结束
打开一个流的时候,这个流上有两个标记值:
1,是否遇到文件末尾
2,是否发生错误
这两种情况是文件读取结束的两种原因
进行读取时使用这两种函数:
1,fgetc--如果读取正常,返回读取到的字符的ASCII码值,如果读取失败或遇到文件末尾,就返回EOF(-1)
2,fgets--如果读取正常,返回存储读取到的字符串的字符数组的地址,如果读取失败或遇到文件末尾,就返回NULL
此时再通过两个函数判断文件读取结束的原因:
1,判断是否遇到文件末尾:int feof(FILE *stream);
如果到达末尾,就返回非零值,没到达末尾就返回0
2,判断是否发生错误:int ferror(FILE *stream);
出现错误,返回非零,没有错误,返回0
运用实例:
2,文件的拷贝
七,文件缓冲区
内存不会直接向硬盘/文件输入数据,而是会先将数据输送到文件缓冲区当中,然后当缓冲区装满时再通过文件缓冲区传入硬盘/文件当中。从磁盘/文件中读取数据也是同理,会先将数据读取到文件缓冲区当中,再将数据逐个传入到程序数据区当中。
文件缓冲区的大小由编译器决定。