1.文件分为 磁盘文件与设备文件。磁盘文件就是我们通常认识的文件。设备文件就是与主机相连的比如摄像头等设备,在linux下还是那句老话‘一切皆文件’。
2.文件的存取:程序与文件的交互,为了提高效率通常设置缓冲区。
3.物理上文件都是二进制,用用户或操作系统看,文件可以分为基于字符编码的文件,或基于二进制的文件。
4.文本文件比如lrc,常见有ascii,unicode,一般可以用文本文档直接打开。二进制文件一般需要根据具体应用,指出某个值是什么意思。
5.二进制译码稍难些,文本文件译码是定长的故容易些,二进制文件比文本文件空间利用率高,文本文件比二进制文件可读性好,二进制文件需要专门的文件解码器,比如读bmp要用专门的读图软件。
6.C语言采用库函数对文件进行操作,基本流程1.用fopen打开文件得到文件指针fp。2.调用有关函数对文件进行处理。3.用完关闭fclose。
7.FILE *是文件指针的类型,stdio.h的定义如下
typedef struct
{
short level;//a缓冲区满或空的程度;
unsigned char flags;//
char fd;//file discription
unsigned char hold;//无缓冲区不读取字符;
short bsize;//buffer size;
unsigned char *buffer;//
unsigned char *curp//current pointer
unsigned istemp;//temp file
short token;//validation
}
在缓冲文件系统中每一个被使用的文件都要在内存中开辟一段FILE类型的区域,存放与操作文件相关的信息。
C中有stdin,stdout,stderr,无须定义打开直接使用。
打开文件 FILE *fp=NULL;
fp=fopen(文件名,文件使用方式);
文件名可以包含路径信息
文件的使用方式 读写文本或二进制
fp文件指针,指向被打开的文件,失败返回空,成功返回相应的指针。
例如:
FILE * fp_pass_wd=NULL;
fp_passwd=fopen("passwdtxt","rt");
if(fp_passwd==NULL)
printf("file open error\n");
文件名可以用相对路径./ ../ 或者在当下路径中直接写文件名 或者 绝对路径 c://test//passwd.txt
权限可以 r w a +;
方式b t(可以省略);
注意:win平台下 以文本方式打开读取文件时将所有\r\n转成\n;写文件把\n转成\r\n; 二进制打开读写都不会进行这样的转换;
linux、unix平台下 原样输入输出;
关闭文件 fclose(FILE * fp);成功返回0;
C语言提供了字节读写函数:fgetc和fputc
字符串读写函数:fgets和fputs
数据块读写函数:fread和fwrite
格式化读写函数:fscanf和fprintf
以上函数可完成对文件内容的顺序读写;
ch=fgetc(fp);//文本文件结尾返回EOF 二进制文件feof判断结尾
fputc(ch,fp);//feof()判断结尾 输出成功返回输出字节 失败返回EOF 在stdio.h中-1;
fgets(str,n,fp); 从fp指向的文件读入n-1个字符 在遇到换行符或EOF读入提前结束在最后加一个\0 str为存放数据的首地址;
fputs(“china”,fp);向指定的文件写一个字符串 \0 不会写到文件中,第一个参数可以是字符串,字符串数组或字符指针;
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
参数说明:buffer 存储数据空间的首地址的指针
size要一次读写的数据块的大小
count要读些的数据块的个数
fp指向要进行写操作的文件指针
返回值(实际读写的数据块数(不是总大小));
fprintf(文件指针,格式字符串,输出列表);
fscanf(文件指针,格式字符串,输入列表);
fprintf与fscanf函数对磁盘文件的读写需要ASCII与二进制的来回转换,费时较多,故在内存磁盘频繁交换数据等情况下尽量用fread,fwrite;
前面介绍的是顺序读写,即读写只能从头开始,顺序读写各个数据;
但在实际问题中常读写文件中的某一指定的部分,如读第200-300个字节;
为解决这个问题可以移动文件内部位置指针到相应的读写位置,在进行读写,这种读写称为随机读写;
实现随机读写的关键是按要求移动指针,这成为文件的定位。
如rewind ftell fseek函数
void rewind(文件指针);
long ftell(文件指针)
取得文件流目前的读写位置,成功返回距离文件起始的字节数,出粗返回-1;
int fseek(文件类型指针,位移量,起始点)
函数功能 移动文件流到指定的位置
起始点:文件开头 SEEK_SET 0
文件当前位置 SEEK_CUR 1
文件末尾 SEEK_END 2
位移量 100 SEEK_SET 从文件头向后移动100字节 -50 SEEK_END 从文件结尾 回退50字节
*********************************************************************************************
fgets从指定的stream中读取字符并把他们复制到buffer中。当读取一个换行符并存储到缓冲区之后便不再读取。如果缓冲区内存储的字符数达到buffer_size-1个时它也停止读取,但是不影响数据的完整性,因为下一次调用fgets将从流的下一个字节开始继续读取。任何情况下,一个NUL字节将被添加到缓冲区结尾,使它成为一个字符串。
如果任何字符在读取之前就到达了文件尾部,缓冲区就不会进行任何修改,fgets函数返回一个NULL指针。否则,fgets返回它的第一个参数(指向返回区的指针)。这个返回值通常检查是否到达了文件尾。
gets读取一行输入时,并不在缓冲区中存储结尾的换行符。当puts写入一个字符串是,它在字符串写入之后再向输出添加一个换行符。
传递给fputs的缓冲区必须包含一个字符串,他的字符被写入流中。这个字符串预期是以NUL字节结尾,所以这个函数没有一个缓冲长度参数。这个字符串是逐字写入的:如果他不包含一个换行符,就不会写入换行符。如果包含了几个换行符,就会写入几个换行符。因此,当fgets每次都读取一整行时,fputs却可以一次写入一行的一部分,也可以一次写入一整行,甚至可以一次写入好几行。如果写入时出现错误,fputs返回常量EOF,否则他将返回一个非负值。
#include
#define MAX_LINE_LENGTH 1024
void copylines(FILE *input,FILE *output)
{
char buffer[MAX_LINE_LENGTH];
while(fgets(buffer,MAX_LINE_LENGTH,input)!=NULL)
{
fputs(buffer,output);
}
}
以上函数从一个文件读入行,并原封不动的把他们写入到另一个文件。常量MAX_LINE_LENGTH决定缓冲区的长度,也就是可以被读取的一行的最大长度。在这个函数中,这个值并不重要,因为不管一次读入,还是分段读入,它所产生的结果文件都是相同的。另一方面,如果函数需要计数被复制的行的数目,太小的缓冲区将会产生一个不正确的计数,因为一个长行可能会被分成数段进行读取 。可以通过增加代码,观察每一段是否以换行符结尾来修正。
gets由于没有缓冲区的长度因此,长的输入行读入短的缓冲区时容易产生溢出。
fscanf()函数(有点像正则表达式):
功 能: 从一个流中执行格式化输入,fscanf遇到空格和换行时结束,注意空格时也结束。
用 法:int fscanf(FILE *stream, char *format,[argument...]);
int fscanf(文件指针,格式字符串,输入列表);
for example:
FILE*fp;
chara[10];
intb;
doublec;
fscanf(fp,"%s%d%lf",a,&b,&c)
返回值:整型,数值等于[argument...]的个数
其中的format就是相当于正则表达式中的格式,即用什么样的格式来分隔文件中的信息。光说不好理解,一下用一个例子来说明具体怎么用:
首先我有一个data。txt的文件里面的数据格式如下:
2,50,41,w,20.585828
4,52,51,r,52.012547
.........................
许多条类似的记录,都是以,来分隔的
.......................
我实现的功能就是把上面文件中的数据的五个字段赋值给相应的五个变量,并且输出这些变量的值。实现的程序如下:
#include