c 文件操作
基础
文件总的来说其实就只有两个操作,打开(关闭)和读写。本文也围绕这两个方面展开
文件格式
文件一般由三部分组成:路径,文件名,后缀。
例:"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);
获得当前指针对于文件开始位置的偏移量