文件
文件概述
存储在内存储器的集合,一般称为表,如数组;而存储在外部介质上的信息集合称为文件,如磁盘文件。
文件通常是驻留在外部介质(如磁盘等)上的,使用时才调入内存。
文件的分类
从用户的角度:普通文件和设备文件
普通文件:驻留在磁盘或其他外部介质上的一个有序数据集,其又分为:
- 程序文件:源文件(后缀为.c)、目标文件(后缀为.obj)、可执行程序(.exe);
- 数据文件:一组待输入处理的原始数据,或者是一组输出的结果。
设备文件:与主机相连的各种外部设备,如显示器、打印机、键盘等。在操作系统中,把外部设备也看做一个文件来进行管理,把它们的输入、输出等同于对磁盘文件的读和写。
通常把显示器定义为标准输出文件,在屏幕上显示有关信息就是向标准输出文件输出;把键盘被指定为标准输入文件,从标准输入文件上输入数据。
从文件编码的方式的角度:ASCII码文件和二进制文件
ASCII码文件:也称为文本文件,这种文件在磁盘中存放时每个字符对于1个字节,用于存放对应的ASCII码,ASCII码文件可在屏幕上按字符显示,因此能够读懂文件内容
ASCII码文件以字符形式存储,读写位复制,需要转换,传输效率低,占用外存空间较大
例如:数1234按ASCII码存储
00110001 00110010 00110011 00110100 //占4个字节
二进制文件:是按二进制的编码方式来存放文件的,只占2个字节,二进制文件虽然也可以在屏幕上显示,但其内容无法读懂
二进制文件的存储形式与数据在内存中的存储形式相同,读写位复制,不需要转换,传输效率高,节省外存空间
例如:数1234按二进制存储
00000100 11010010 //占2个字节
读写文件
写文件
- 是从内存向磁盘输出数据。首先将内存中的数据送到文件缓冲区,待文件缓冲区满后写入磁盘
读文件
- 是从磁盘读取数据存入内存。首先从磁盘读出一批数据送到文件缓冲区,然后从文件缓冲区取出数据存入内存
文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用
文件名包含3个部分:文件路径+文件名主干+文件后缀 例如:
c:\code\test.txt文件标识常被称为文件名
文件类型指针
文件缓冲区:每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态以及文件当前的位置),这些信息是保存在一个结构体变量之中;
该结构体类型是有系统声明的,取名
FIEL文件指针:在C语言中用一个指针变量指向一个文件,通过文件指针就可以对它所指的文件进行各种操作。
一般通过一个FILE的指针来维护这个FILE结构的变量
文件指针定义的一般格式:
FILE 文件指针其中:
FILE是文件缓冲区的类型名,必须大写;“文件指针”是指向文件缓冲区的指针例如:
FILE* pf;//文件指针变量定义
pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件(通过文件指针能够找到与他关联的文件)
文件基本操作
文件处理必须包含3个基本过程:打开文件,读或写、关闭文件;
在C语言中,文件操作都是由库函数来完成的
文件的打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件
- 打开文件:建立文件的各种有关信息,并使文件指针指向该文件,以便进行其他操作
- 关闭文件:断开指针与文件之间的联系,也就禁止了再对文件进行操作
打开文件需调用库 fopen 函数:
一般调用格式:
FILE * fopen ( const char * filename, const char * mode );filename是指定打开的文件名,可以包含盘符、路径、文件名,是字符串mode指定打开的文件读写方式,是字符串,必须小写;返回指定打开的文件的指针
mode如下:文件使用方式 含义 如果指定文件不存在 “ r ”(只读) 为了输入数据,打开一个已经存在的文本文件 出错 “ w ”(只写) 为了输入数据,打开一个文本文件 建立一个新的文件 “ a ”(追加) 向文本文件尾添加数据 建立一个新的文件 “ r+ ”(读写) 为了读和写,打开一个文本文件 出错 “ w+ ”(读写) 为了读和写,建立一个新的文件 建立一个新的文件 “ a+ ”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件 “ rb ”(只读) 为了输入数据,打开一个二进制文件 出错 “ wb ”(只写) 为了输入数据,打开一个二进制文件 建立一个新的文件 “ ab ”(追加) 向一个二进制文件尾添加数据 出错 “ rb+ ”(读写) 为了读和写,打开一个二进制文件 出错 “ wb+ ”(读写) 为了读和写,建立一个新的二进制文件 建立一个新的文件 “ ab+ ”(读写) 打开一个二进制文件,在文件尾进行读写 建立一个新的文件
关闭文件需调用库 fclose 函数:
- 一般调用形式:
int fclose ( FILE * stream );
- 一般调用形式:
例:
#include <stdio.h> int main() { //打开文件 FILE* pf = fopen("test.dat", "w"); if (pf == NULL) { perror("fopen"); return 0; } //关闭文件 fclose(pf); pf = NULL; return 0; }
文件的顺序读写
对文件的读和写是最常用的文件操作。在C语言中提供了多种文件读写的函数;使用这些函数需要包含头文件
stdio.h注明:对这些函数的使用只是简单的说明,更加详细的内容可以到 cplusplus.com - The C++ Resources Network 查询
在讲这些函数之前,我们先讲一下 “流” 是什么?
流(stream)是一个很抽象的概念,通常认为:流是磁盘或其它外围设备关联的数据的源或目的地
通俗的讲,我们写了一个程序,我们可以把它的数据传到屏幕、硬盘、U盘、光盘、网络、软盘上,而这些硬件的读写方式不同,所以我们在程序和这些硬件之间,抽象出一个空间,这个空间就是**“流”**,这样我们只需要将程序的数据传到“流”里面,然后再传到不同的硬件。
在C语言程序中,我们默认打开了3个流,即
stdin - 标准输入流 - 键盘
stdout - 标准输出流 - 屏幕
stderr - 标准出错流 - 屏幕
这3个流的类型是
FIEL*文件读写函数:
字符读写函数:
fgetc和fputc(适用于所有输入流和输出流)字符串读写函数:
fgets和fputs(适用于所有输入流和输出流)格式化读写函数:
fscanf和fprintf(适用于所有输入流和输出流)数据块读写函数:
fread和fwrite(只适用于文件)
fgetc函数:从指定的磁盘文件中读一字符。调用格式:
int fgetc ( FILE * stream );返回值:读取成功,返回字符值;读取失败,返回EOF(-1)
注意:EOF只适用于ASCII码文件
fputc函数:将一个字符写到指定的磁盘文件。调用格式:
int fputc ( int character, FILE * stream );返回值:写成功,返回字符值;写失败,返回EOF(-1)
fgets函数:从指定的磁盘文件中读一字符串。调用格式:
char * fgets ( char * str, int num, FILE * stream );返回值:读成功,返回字符串的首地址;读失败或者遇到文件结束符,返回EOF(-1)
注意:其实只能读取 num-1 个字符数,因为有\0
fputs函数:将一个字符串写到指定的磁盘文件。调用格式:
int fputs ( const char * string, FILE * stream );返回值:写成功,返回0;写失败,返回EOF(-1)
fprintf函数:将一个数据块写到指定的磁盘文件。调用格式:
int fprintf ( FILE * stream, const char * format, ... );fscanf函数:从指定的硬盘文件中读一个数据块调用格式:
int fscanf ( FILE * stream, const char * format, ... );fwrite函数:将一个数据块写到指定的磁盘文件。调用格式:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );返回值:写成功,返回数据项数目;写失败,返回0;
fread函数:从指定的磁盘文件读一个数据块。调用格式:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );返回值:读成功,返回数据项数目;读失败或遇到文件结束符,返回0;
例:
例1:
#include <stdio.h> int main() { FILE* pf = fopen("test.dat", "w"); if (pf == NULL) { perror("fopen"); return 0; } //写文件 fputc('d', pf); //写单个字符 fputs("我爱美女", pf); //写文本行 //关闭文件 fclose(pf); pf = NULL; return 0; }例2:
//运用C语言标准输出流 stdout #include <stdio.h> int main() { FILE* pf = fopen("test.dat", "w"); if (pf == NULL) { perror("fopen"); return 0; } //写文件 fputs("我爱美女", stdout); //关闭文件 fclose(pf); pf = NULL; return 0; }例3:
#include <stdio.h> int main() { char arr[20] = { 0 }; FILE* pf = fopen("test.dat", "r"); 打开一个文件 if (pf == NULL) { perror("fopen"); return 0; } //写文件 fgets(arr, 20, pf); //fgets函数的使用 printf("%s", arr); //关闭文件 fclose(pf); pf = NULL; return 0; }//编译结果:我爱美女 在test.dat文件里面是 :我爱美女
文件的随机读写
- 移动文件内部的位置指针到需要读写的位置,再进行读写,这种读写称为随机读写
- 实现随机读写的关键是要按照要求移动位置指针,这称为文件的定位
实现文件随机读写的函数
fseek函数:控制当前文件指针的移动调用格式:
int fseek ( FILE * stream, long offset, int origin );返回值:操作成功,返回0;操作失败,返回非0值
对于起始点:
起始点 名称 代码 文件开始 SEEK_SET 0 文件当前位置 SEEK_CUR 1 文件末尾 SEEK_END 2 若以文件开始为基准,偏移量只能是正值,若以文件末尾为基准,偏移量只能是负值,若以文件当前位置(即文件当前指针)为基准,偏移量可以是正值,也可以是负值。
例:
#include <stdio.h> int main() { //打开文件 FILE* pf = fopen("data.dat", "wb"); if (pf == NULL) { perror("fopen"); return 0; } //读写文件 fputs("This is an apple.", pf); //data.dat文件内容是:This is an apple fseek(pf, 9, 0); fputs(" sam", pf); //此时data.dat文件内容是:This is an sample //关闭文件 fclose(pf); pf == NULL; return 0; }ftell函数:返回指针相对于起始位置的偏移量调用格式:
long int ftell ( FILE * stream );返回值:偏移量
rewind函数:让文件指针的位置回到文件的起始位置调用格式:
void rewind ( FILE * stream );
文本文件和二进制文件
- 根据数据的组织形式,数据文件被称为ASCII码文件(文本文件)或者二进制文件
- 二进制文件:数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件
- 文本文件:要求在外存上以ASCII码的形式存储,则需要在存储前转换,以ASCII字符形式存储的文件就是文本文件
- 一个数据在文件中是怎么存储的呢?
- 字符一律以ASCII码形式存储;数值型数据既可以用ASCII码形式存储,也可以使用二进制形式存储
文件读取结束的判定
feof函数:判断文件是否是结束符。调用格式:
int feof ( FILE * stream );返回值:如果遇到文件结束符,返回值为非0;未遇到文件结束符,返回值为0
从键盘读入数据,按 Ctrl+Z (显示器显示^Z),即输入文件结束符。
feof函数可用于二进制文件和ASCII码文件在文件读取过程中,不能用
feof函数的返回值直接用来判断文件是否结束,而是应用于当文件读取结束时,判断是读取失败而结束,还是遇到文件尾结束- 文本文件读取是否结束,判断返回值是否为
EOF(fgetc)或者NULL(fgets) - 二进制文件的读取结束的判断,判断返回值是否小于实际要读的个数。
- 文本文件读取是否结束,判断返回值是否为