在 C 语言中 ‘\‘ 一般是转义字符的起始标志,故在路径中需要用两个 ‘\‘ 表示路径中目录层次的间隔,也可以使用 ‘/‘ 作为路径中的分隔符。
文件按其逻辑结构可分为:记录文件和流式文件。而记录文件又可分为:顺序文件、索引文件、索引顺序文件及散列文件等。
流是磁盘或其它外围设备中存储的数据的源点或终点。流按方向分为:输入流和输出流。从文件获取数据的流称为输入流,向文件输出数据称为输出流。
流按数据形式分为:文本流和二进制流。文本流是 ASCII 码字符序列,而二进制流是字节序列。
文本文件与二进制文件
根据文件中数据的组织形式的不同,可以把文件分为:文本文件和二进制文件。
文本文件:把要存储的数据当成一系列字符组成,把每个字符的 ASCII 码值存入文件中。每个 ASCII 码值占一个字节,每个字节表示一个字符。故文本文件也称作字符文件或 ASCII 文件,是字符序列文件。
二进制文件:把数据对应的二进制形式存储到文件中,是字节序列文件。
文件读写
在 UNIX 和 Linux 系统中,无论是二进制文件还是文本文件,均是以单字节 LF(0x0A) 即作为文件中的换行符。
由于 C 语言是在 UNIX 系统上提出并发展起来的,故 C 语言中的换行规则与 UNIX 系统文件中的换行规则是一致的,使用 LF 即 ‘\n‘ 表示换行。因此 C 语言程序访问 UNIX/Linux 系统中的文件时,可直接访问,不需要转换。
而在 DOS/Windows 系统中,文本文件使用 ASCII 值为 13(0x0D) 的回车符 CR(Carriage-Return) 以及 ASCII 值为 10(0x0A) 的换行符 LF(Line-Feed) 这两个符号,即双字节 CR-LF(0x0D 0x0A) 的 ‘r‘、‘\n‘ 作为文本文件的换行符。与 C 语言程序中的换行符不一致。
因此,若使用 C 语言程序访问 DOS/Windows 系统中的文本文件,针对换行符的差异,就必须多一层转换。如果把 C 程序中数据以文本的方式写入文件时,需要把 C 程序中的 ‘\n‘ 转换为 ‘r‘ 和 ‘\n‘ 这两个字符后,再写入文本文件;当 C 程序以文本方式读取文本文件中的数据时,需要把文本文件中连续出现的两个字符 ‘r‘、‘\n‘ 转换为一个字符 ‘\n‘ 后,送给 C 程序。
说明:DOS/Windows 系统的文本文件中,回车 ‘\r‘ 和换行 ‘\n‘ 的含义如下:
回车‘\r‘:表示光标回到该行的行首处。
换行‘\n‘:表示光标从当前行该列位置移动到下一行对应的该列位置。
缓冲和非缓冲文件系统
C语言中文件系统可分为两大类,一种是缓冲文件系统也称为标准文件系统,另一种是非缓冲文件系统。ANSI C 标准中只采用缓冲文件系统。
缓冲文件系统:系统自动为每个打开的文件在内存开辟一块缓冲区,缓冲区的大小一般由系统决定。当程序向文件中输出(写入)数据时,程序先把数据输出到缓冲区,待缓冲区满或数据输出完成后,再把数据从缓冲区输出到文件;当程序从文件输入(读取)数据时,先把数据输入到缓冲区,待缓冲区满或数据输人完成后,再把数据从缓冲区逐个输入到程序。
非缓冲文件系统:系统不自动为打开的文件开辟内存缓冲区,由程序设计者自行设置缓冲区及大小。
程序每一次访问磁盘等外存文件都需要移动磁头来定位磁头扇区,如果程序频繁地访问磁盘文件,会缩短磁盘的寿命,况且速度较慢,与快速的计算机内存处理速度不匹配。
带缓冲区文件系统的好处是减少对磁盘等外存文件的操作次数,先把数据读取(写入)到缓冲区中,相当于把缓冲区中的数据一次性与内存交互,提髙了访问速度和设备利用率。
一般把带缓冲文件系统的输入输出称作标准输入输出(标准 I/O),而非缓冲文件系统的输入输出称为系统输入输出(系统 I/O)。
ANSI C 为正在使用的每个文件分配一个文件信息区,该信息区中包含文件描述信息、 该文件所使用的缓冲区大小及缓冲区位置、该文件当前读写到的位置等基本信息。这些信息保存在一个结构体类型变量中,该结构体类型为 FILE 在 stdio.h 头文件中定义,不允许用户改变。
每个 C 编译系统 stdio.h 文件中的 FILE 定义可能会稍有差别,但均包含文件读写的基本信息。
文件的打开与关闭
本节所涉及的文件如无特殊说明均指缓冲文件系统文件,即 ANSI C 标准文件。C 程序中对任何文件进行操作,都必须先“打开”文件,即打开流;操作完成后,需“关闭”文件,即关闭流。
这里的“打开”和“关闭”可调用标准库 stdio.h 中的 fopen 和 fclose 函数实现。
打开函数 fopen 的原型如下。
FILE * fopen(char *filename, char *mode);
函数参数:
filename:文件名,包括路径,如果不显式含有路径,则表示当前路径。例如,“D:\\f1.txt”表示 D 盘根目录下的文件 f1.txt 文件。“f2.doc”表示当前目录下的文件 f2.doc。
mode:文件打开模式,指出对该文件可进行的操作。常见的打开模式如 “r” 表示只读,“w” 表示只写,“rw” 表示读写,“a” 表示追加写入。更多的打开模式如表 2 所示。
模式 | 含 义 | 说 明 |
---|---|---|
r | 只读 | 文件必须存在,否则打开失败 |
w | 只写 | 若文件存在,则清除原文件内容后写入;否则,新建文件后写入 |
a | 追加只写 | 若文件存在,则位置指针移到文件末尾,在文件尾部追加写人,故该方式不 删除原文件数据;若文件不存在,则打开失败 |
r+ | 读写 | 文件必须存在。在只读 r 的基础上加 ‘+‘ 表示增加可写的功能。下同 |
w+ | 读写 | 新建一个文件,先向该文件中写人数据,然后可从该文件中读取数据 |
a+ | 读写 | 在” a”模式的基础上,增加可读功能 |
rb | 二进制读 | 功能同模式”r”,区别:b表示以二进制模式打开。下同 |
wb | 二进制写 | 功能同模式“w”。二进制模式 |
ab | 二进制追加 | 功能同模式”a”。二进制模式 |
rb+ | 二进制读写 | 功能同模式"r+”。二进制模式 |
wb+ | 二进制读写 | 功能同模式”w+”。二进制模式 |
ab+ | 二进制读写 | 功能同模式” |
返回值:打开成功,返回该文件对应的 FILE 类型的指针;打开失败,返回 NULL。故需定义 FILE 类型的指针变量,保存该函数的返回值。可根据该函数的返回值判断文件打开是否成功。
返回值。可根据该函数的返回值判断文件打开是否成功。
关闭函数 fclose :
int fclose(FILE *fp);
函数参数:
fp:已打开的文件指针。
返回值:正常关闭,返回否则返回 EOF(-1)。
文件的顺序读写
对文件读取操作完成后,如果从文件中读取到的每个数据的顺序与文件中该数据的物理存放顺序保持一致,则称该读取过程为顺序读取;同理,对文件写入操作完成后,如果文件中所有数据的存放顺序与各个数据被写入的先后顺序保持一致,则称该写入过程为顺序写入。
字符输入输出
c 语言中提供了从文件中逐个输入字符及向文件中逐个输出字符的顺序读写函数 fgetc 和 fputc 及调整文件读写位置到文件开始处的函数 rewind。这些函数均在标准输入输出头文件 stdio.h 中。
字符输入函数 fgetc 的函数原型为:
int fgetc (FILE *fp);
函数功能:从文件指针 fp 所指向的文件中输入一个字符。输入成功,返回该字符;已读取到文件末尾,或遇到其他错误,即输入失败,则返回文本文件结束标志 EOF(EOF 在 stdio.h 中已定义,一般为 -1)。
注意:由于 fgetc 是以 unsigned char 的形式从文件中输入(读取)一个字节,并在该字节前面补充若干 0 字节,使之扩展为该系统中的一个 int 型数并返回,而非直接返回 char 型。当输入失败时返回文本文件结束标志 EOF 即 -1,也是整数。故返回类型应为 int 型,而非 char 型。
如果误将返回类型定义为 char 型,文件中特殊字符的读取可能会出现意想不到的逻辑错误。
由于在 C 语言中把除磁盘文件外的输入输出设备也当成文件处理,故从键盘输入字符不仅可以使用宏 getchar() 实现,也可以使用 fgetc (stdin) 实现。其中,stdin 指向标准输入设备—键盘所对应的文件。stdin 不需要人工调用函数 fopen 打开和 fclose 关闭。
字符输出函数 fputc 的函数:
int fputc (int c, FILE *fp);
函数功能:向 fp 指针所指向的文件中输出字符,输出成功,返回该字符;输出失败,则返回 EOF(-1)。
向标准输出设备屏幕输出字符变量 ch 中保存的字符,不仅可以使用宏 putchar(ch) 实现,也可以使用 fputc (ch,stdout); 实现。其中,stdout 指向标准输出设备—显示器所对应的文件。stdout 也不需要人工调用函数 fopen 打开和 fclose 关闭。
从键盘输入若干个字符,同时把这些字符输出到 D 盘根目录下的文件 data_file.txt 中及屏幕上。各个字符连续输入,最后按下回车键结束输入过程:
#include<stdio.h> #include<stdlib.h> int main (void) { char file_name[20]="D:/data—file.txt"; FILE * fp=fopen (file_name, "w") ; //打开文件 int c; //c:接收fgetc的返回值,定义为int,而非char M if(NULL==fp) { printf ("Failed tO open the file !\n"); exit(0); } printf ("请输入字符,按回车键结束:"); while ((c=fgetc (stdin)) != ‘\n‘) //stdin:指向标准输人设备键盘文件 { fputc (c, stdout); //stdout:指向标准输出设备显示器文件 fputc(c,fp); } fputc (‘\n‘, stdout); fclose (fp); //关闭文件 return 0; }
文件读写位置复位函数 rewind 的函数:
void rewind (FILE *fp);
函数功能:把 fp 所指向文件中的读写位置重新调整到文件开始处。
字符串输入输出
字符串输入函数 fgets:
char * fgets (char *s, int size, FILE * fp);
函数功能:从 fp 所指向的文件内,读取若干字符(一行字符串),并在其后自动添加字符串结束标志 ‘\0‘ 后,存入 s 所指的缓冲内存空间中(s 可为字符数组名),直到遇到回车换行符或已读取 size-1 个字符或已读到文件结尾为止。该函数读取的字符串最大长度为 size-1。
参数 fp:可以指向磁盘文件或标准输入设备 stdin。
返回值:读取成功,返回缓冲区地址 s;读取失败,返回 NULL。
说明:fgets 较之 gets 字符串输入函数是比较安全规范的。因为 fgets 函数可由程序设计者自行指定输入缓冲区 s 及缓冲区大小 size。即使输入的字符串长度超过了预定的缓冲区大小,也不会因溢出而使程序崩溃,而是自动截取长度为 size-1 的串存入 s 指向的缓冲区中。
字符串输出函数 fputs :
int fputs (const char *str, FILE *fp);
函数功能:把 str(str 可为字符数组名)所指向的字符串,输出到 fp 所指的文件中。
返回值:输出成功,返回非负数;输出失败,返回EOF(-1)。
格式化输入输出
文件操作中的格式化输入输出函数 fscanf 和 fprintf 一定意义上就是 scanf 和 printf 的文本版本。程序设计者可根据需要采用多种格式灵活处理各种类型的数据,如整型、字符型、浮点型、字符串、自定义类型等。
文件格式化输入函数 fscanf :
int fscanf (文件指针,格式控制串,输入地址表列);
函数功能:从一个文件流中执行格式化输入,当遇到空格或者换行时结束。注意该函数遇到空格时也结束,这是其与 fgets 的区别,fgets 遇到空格不结束。
返回值:返回整型,输入成功时,返回输入的数据个数;输入失败,或已读取到文件结尾处,返回 EOF(-1)。
故一般可根据该函数的返回值是否为 EOF 来判断是否已读到文件结尾处。
格式化输出函数 fprintf :
int fprintf (文件指针,格式控制串,输出表列);
函数功能:把输出表列中的数据按照指定的格式输出到文件中。
返回值:输出成功,返回输出的字符数;输出失败,返回一负数。
二进制方式读写数据块
数据块读取(输入)函数 fread :
unsigned fread (void *buf, unsigned size, unsigned count, FILE* fp);
函数功能:从 fp 指向的文件中读取 count 个数据块,每个数据块的大小为 size。把读取到的数据块存放到 buf 指针指向的内存空间中。
返回值:返回实际读取的数据块(非字节)个数,如果该值比 count 小,则说明已读到文件尾或有错误产生。这时一般采用函数 feof 及 ferror 来辅助判断。
函数参数:
buf:指向存放数据块的内存空间,该内存可以是数组空间,也可以是动态分配的内存。void类型指针,故可存放各种类型的数据,包括基本类型及自定义类型等。
size:每个数据块所占的字节数。
count:预读取的数据块最大个数。
fp:文件指针,指向所读取的文件。
数据块写入(输出)函数 fwrite :
unsigned fwrite (const void *bufAunsigned size,unsigned count,FILE* fp);
函数功能:将 buf 所指向内存中的 count 个数据块写入 fp 指向的文件中。每个数据块的大小为 size。
返回值:返回实际写入的数据块(非字节)个数,如果该值比 count 小,则说明 buf 所指空间中的所有数据块已写完或有错误产生。这时一般采用 feof 及 ferror 来辅助判断。
函数参数:
- buf:前加const的含义是buf所指的内存空间的数据块只读属性,避免程序中有意或无意的修改。
- size:每个数据块所占的字节数。
- count:预写入的数据块最大个数。
- fp:文件指针,指向所读取的文件。
注意:使用 fread 和 fwrite 对文件读写操作时,一定要记住使用“二进制模式”打开文件,否则,可能会出现意想不到的错误。
feof 函数来判断是否到达文件结尾:
int feof (FILE * fp);
函数功能:检查 fp 所关联文件流中的结束标志是否被置位,如果该文件的结束标志已被置位,返回非 0 值;否则,返回 0。
需要注意的是:
1) 在文本文件和二进制文件中,均可使用该函数判断是否到达文件结尾。
2) 文件流中的结束标志,是最近一次调用输入等相关函数(如 fgetc、fgets、fread 及 fseek 等)时设置的。只有最近一次操作输入的是非有效数据时,文件结束标志才被置位;否则,均不置位。
fseek 指定位置读写:
int fseek(FI:LE *fp, long offset, int origin);
函数功能:把文件读写指针调整到从 origin 基点开始偏移 offset 处,即把文件读写指针移动到 origin+offset 处。
函数参数:
1) origin:文件读写指针移动的基准点(参考点)。基准位置 origin 有三种常量取值:SEEK_SET、SEEK_CUR 和 SEEK_END,取值依次为 0,1,2。
SEEK_SET:文件开头,即第一个有效数据的起始位置。
SEEK_CUR:当前位置。
SEEK_END:文件结尾,即最后一个有效数据之后的位置。注意:此处并不能读取到最后一个有效数据,必须前移一个数据块所占的字节数,使该文件流的读写指针到达最后一个有效数据块的起始位置处。
2) offset:位置偏移量,为 long 型,当 offset 为正整数时,表示从基准 origin 向后移动 offset 个字节的偏移;若 offset 为负数,表示从基准 origin 向前移动 |offset| 个字节的偏移。
返回值:成功,返回 0;失败,返回 -1。
例如,若 fp 为文件指针,则 seek (fp,10L,0); 把读写指针移动到从文件开头向后 10 个字节处。 fSeek(fp,10L,1); 把读写指针移动到从当前位置向后 10 个字节处。 fseek(fp,-20L,2); 把读写指针移动到从文件结尾处向前 20 个字节处。
获取文件指针位置 ftell:
long ftell (FILE *fp);
原文地址:https://www.cnblogs.com/xuey/p/12207656.html