基础

文件总的来说其实就只有两个操作,打开(关闭)和读写。本文也围绕这两个方面展开

文件格式

文件一般由三部分组成:路径,文件名,后缀。

例:"E:\\ch10.doc"或者"E:/ch10.doc"

之所以要两个\是因为在c语言中\作为转义字符。

流按方向分为:输入流和输出流。从文件获取数据的流称为输入流,向文件输出数据称为输出流。

例如,从键盘输入数据然后把该数据输出到屏幕上的过程,相当于从一个文件输入流(与键盘相关)中输入(读取)数据,然后通过另外一个文件输出流(与显示器相关)把获取的数据输出(写入)到文件(显示器)上。

换行符

在Linux系统中,换行符是0x0a(LF)。因为c是在unix上发展起来的,所以访问Linux文件时,不需要转换,直接可以访问。

在windows系统中使用0x0d(CR ‘\r’) 和 0x0a(LF ‘\n’)合起来作为换行符。所以把windows下文件给c程序还要先把CR-LF转换成LF

缓冲文件系统

缓冲文件系统:系统自动为每个打开的文件在内存开辟一块缓冲区,缓冲区的大小一般由系统决定。当程序向文件中输出(写入)数据时,程序先把数据输出到缓冲区,待缓冲区满或数据输出完成后,再把数据从缓冲区输出到文件;当程序从文件输入(读取)数据时,先把数据输入到缓冲区,待缓冲区满或数据输人完成后,再把数据从缓冲区逐个输入到程序。

c语言就是用的缓冲文件系统。其实这和vim有点像。

ANSI C 为正在使用的每个文件分配一个文件信息区,该信息区中包含文件描述信息、 该文件所使用的缓冲区大小及缓冲区位置、该文件当前读写到的位置等基本信息。这些信息保存在一个结构体类型变量中,该结构体类型为 FILE 在 stdio.h 头文件中定义,不允许用户改变。

文件打开和关闭

文件指针 file* 用来引用一个文件。

打开

原型:FILE * fopen(char *filename, char *mode);

filename指的是文件名,可以包括路径。

mode是打开方式。下面列举了一些打开方式

模式 含 义 说 明
r 只读 文件必须存在,否则打开失败
w 只写 若文件存在,则清除原文件内容后写入;否则,新建文件后写入
a 追加只写 若文件存在,则位置指针移到文件末尾,在文件尾部追加写人,故该方式不 删除原文件数据;若文件不存在,则打开失败
r+ 读写 文件必须存在。在只读 r 的基础上加 ‘+’ 表示增加可写的功能。下同
w+ 读写 新建一个文件,先向该文件中写人数据,然后可从该文件中读取数据
a+ 读写 在” a”模式的基础上,增加可读功能
rb 二进制读 功能同模式”r”,区别:b表示以二进制模式打开。下同
wb 二进制写 功能同模式“w”。二进制模式
ab 二进制追加 功能同模式”a”。二进制模式
rb+ 二进制读写 功能同模式”r+”。二进制模式
wb+ 二进制读写 功能同模式”w+”。二进制模式
ab+ 二进制读写 功能同模式”a+”。二进制模式

按照mode 规定的方式,打开由pname指定的文件。若找不到由pname指定的相应文件,就按以下方式之一处理:

(1) 此时如mode 规定按写方式打开文件,就按由pname指定的名字建立一个新文件;
(2) 此时如mode 规定按读方式打开文件,就会产生一个错误。

例: fopen(“example.txt”, “rw”);

如果返回失败,那么将返回NULL。

关闭

int fclose(FILE *fp);

如果关闭不正常,返回-1(EOF).

文件读写

按字符输入输出

原型:int fgetc (FILE *fp);

作用:一次读入一个字符。如果读入出现问题,返回-1(EOF)

注意:由于 fgetc 是以 unsigned char 的形式从文件中输入(读取)一个字节,并在该字节前面补充若干 0 字节,使之扩展为该系统中的一个 int 型数并返回,而非直接返回 char 型。当输入失败时返回文本文件结束标志 EOF 即 -1,也是整数。故返回类型应为 int 型,而非 char 型。

也就是说最好不要用char类型去接收字符而使用unsigned_char,这样在碰到特殊字符就不会出现错误。

由于在 C 语言中把除磁盘文件外的输入输出设备也当成文件处理,故从键盘输入字符不仅可以使用宏 getchar() 实现,也可以使用 fgetc (stdin) 实现。其中,stdin 指向标准输入设备—键盘所对应的文件。stdin 不需要人工调用函数 fopen 打开和 fclose 关闭。

按字符输出

原型: int fputc (int c, FILE *fp);

向fp文件中输出字符c。如果想输出到屏幕,可以fputc(c, stdout)

对一个文件进行读写操作时,经常会把一个文件中读写位置重新调整到文件的开始处,可以使用函数 rewind 实现。

原型: void rewind (FILE *fp);

作用:把读写位置跳到函数开头。

按字符串输入输出

输入

原型: char * fgets (char *s, int size, FILE * fp);

作用: 从文件中读取长度为size(到了末尾会终止)的字符串,并且自动加入’\0’后输出,遇到空格不会终止。

输出

原型: int fputs (const char *str, FILE *fp);

作用:把str输出到文件中。

格式化输入输出

这个与scanf和printf类似,只是目标变成了文件。

输入

原型: int fscanf (文件指针,格式控制串,输入地址表列);

作用:从文件中输入到格式化字符串中,遇到空格会终止输入。

返回值:返回整型,输入成功时,返回输入的数据个数;输入失败,或已读取到文件结尾处,返回 EOF(-1)

例: fscanf (fp,”%d,%d”, &a, &b); //两个%d之间也必须用逗号隔开

输出

int fprintf (文件指针,格式控制串,输出表列);

作用: 把格式字符串中的数据输出到文件中。

二进制读写

输入

原型:unsigned fread (void *buf, unsigned size, unsigned count, FILE* fp);

作用:从 fp 指向的文件中读取 count 个数据块,每个数据块的大小为 size。把读取到的数据块存放到 buf 指针指向的内存空间中。

返回值:返回实际读取的数据块(非字节)个数,如果该值比 count 小,则说明已读到文件尾或有错误产生。这时一般采用函数 feof 及 ferror 来辅助判断。

输出

原型:unsigned fwrite (const void *buf,unsigned size,unsigned count,FILE* fp);

作用: 把buf中count个大小为size的数据块写到文件中

文件检查

原型: int feof (FILE * fp);

作用:检查是否到了文佳末尾,如果到了,返回非0

随机读写

随机读写就是不是在文件开头而是制定一个位置开始读写。首先要把文件指针移到对应位置,然后开始读写。

原型: int fseek(FILE *fp, long offset, int origin);

作用:把fp读写指针设置到origin+offset的位置上,origin是起始位置。offset是偏移量。

起始位置有三种快捷的设置。分别是:

  • SEEK_SET:文件开头,即第一个有效数据的起始位置。
  • SEEK_CUR:当前位置。
  • SEEK_END:文件结尾,即最后一个有效数据之后的位置。注意:此处并不能读取到最后一个有效数据,必须前移一个数据块所占的字节数,使该文件流的读写指针到达最后一个有效数据块的起始位置处。

可以通过long ftell (FILE *fp);获得当前指针对于文件开始位置的偏移量