C 语言文件操作
简单记录一下 C 语言的文件操作的相关内容。
前期准备
1 | // stdio.h 提供了 C 语言中的许多 IO,当然包括文件 IO |
打开文件 fopen ()
函数名称:fopen
参数:待打开文件的名称(包含该文件名的字符串地址),打开文件的模式;
返回值:成功打开文件则返回一个文件指针,否则返回空指针(NULL)
例如:
1 | FILE *fp; |
需要注意,该函数第二个参数是一个字符串,可能的值如下(表来自《C Primer Plus(第 6 版)中文版》P357 表 13.1):
模式字符串 | 含义 |
---|---|
"r" | 以读模式打开文件 |
"w" | 以写模式打开文件,把现有文件长度截为 0,如果文件不存在,则创建一个新文件 |
"a" | 以写模式打开文件,在现有文件末尾添加内容,如果文件不存在,则创建一个新文件 |
"r+" | 以更新模式打开文件(即可以读写文件) |
"w+" | 以更新模式打开文件,如果文件存在,则将其长度截为 0,如果文件不存在则创建一个新文件 |
"a+" | 以更新模式打开文件,在现有文件的末尾添加内容,如果文件不存在则创建一个新文件,可以读整个文件,但只能从末尾添加内容 |
"rb"、"wb"、"ab"、"rb+"、"r+b"、"wb+"、"w+b"、"ab+"、"a+b" | 与上边的对应类似,但以二进制模式打开文件 |
"wx"、"wbx"、"w+x"、"wb+x" 或 "w+bx" | (C11)与上边对应类似,但如果文件已存在或以独占模式打开文件,则打开文件失败 |
带字母 x 的写模式比以前的具有更多特性:
- 如果以传统的一种写模式打开一个现有文件,fopen () 会把该文件的长度截为 0,这样就丢失了该文件的内容。但是使用带 x 字母的写模式,即使 fopen () 操作失败,原文件的内容也不会被删除;
- 如果环境允许,x 模式的独占特性使得其他程序或线程无法访问正在被打开的文件。
关闭文件 fclose ()
函数名称:fclose
参数:待关闭文件的名称(包含该文件名的字符串地址);
返回值:成功关闭返回 0,否则返回 EOF。
读写文件
fprintf () 和 fscanf ()
这两个函数分别和 printf () 和 scanf () 类似,只不过 printf () 和 scanf () 分别默认了写和读的标准文件是 stdout 和 stdin,而 fprintf () 和 fscanf () 的第一个参数都需要指定文件指针。
getc () 和 putc ()
这两个函数分别和 getchar () 和 putchar () 类似,只是需要提供文件指针。
ungetc()
函数名称:ungetc
函数原型:int ungetc(int c, FILE *fp);
函数作用:把 c 指定的字符放回输入流中
返回值:如果成功,则返回被推入的字符,否则返回 EOF
fgets () 和 fputs ()
虽然这两个函数也分别类似于 gets () 和 puts (),但比起上边几个函数的 "类似",这个要低一点,所以详细说明一下。
函数名称:fgets
函数原型:char *fgets (char * restrict str, int n, FILE * restrict fp);
返回值:如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。如果发生错误,返回一个空指针。
需要注意 fgets () 的第二个参数,因为 fgets () 读取输入知道第一个换行符的后边(意味着它会读入换行符),或读到文件结尾,或读取 n-1 个字符,并在结尾加上一个 \0
使之成为一个字符串。
函数名称:fputs
函数原型:int fputs (char * restrict str, FILE * restrict fp);
返回值:该函数返回一个非负值,如果发生错误则返回 EOF。
fputs () 与 puts () 类似,但不会在结尾自动添加换行。
fread () 和 fwrite ()
上述的函数都是以文本形式读写文件,这两个函数用于以二进制形式读写文件。
函数名称:fread
函数原型:size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict fp);
返回值:返回成功读取项的数量。正常情况下返回值等于 nmemb,发生错误则返回值小于 nmemb。
函数名称:fwrite
函数原型:size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb, FILE * restrict fp);
返回值:返回成功写入项的数量。正常情况下返回值等于 nmemb,发生错误则返回值小于 nmemb。
参数 size 表示待写入数据块的大小(以字节为单位),nmemb 表示待写入数据块的数量。
下边是两个使用这两个函数的例子。
1 | // 保存一个大小为 256 字节的 buffer 数组 |
随机访问 fseek () 和 ftell ()
函数名称:fseek
函数原型:int fseek(FILE *_File,long _Offset,int _Origin);
参数:文件指针,偏移量 (long 类型),模式
返回值:正常则返回 0,错误则返回 -1。
第二个参数偏移量必须是一个 long 类型的值,代表偏移的字节数。这个值为正,则表示像文件末尾方向移动;为负则表示向文件开头处。
第三个参数可以理解成起点位置,可以使用 SEEK_SET
、SEEK_CUR
或 SEEK_END
分别定位到文件开始、当前位置或文件末尾(老版本应分别使用 0
、1
、2
)。
下边是一些例子(来自《C Primer Plus(第 6 版)中文版》P364):
1 | fseek(fp, 0L, SEEK_SET); // 定位至文件开始处 |
函数名称:ftell
函数原型:long ftell(FILE *_File);
返回值:返回当前位置距文件开始的字节数,如文件的第一个字节到文件开始处的距离为 0。
下边是书中给出的一个例子:
1 | fseek(fp, 0L, SEEK_END); // 首先定位到文件结尾 |
其他函数
刷新缓冲区 fflush ()
函数名称:fflush
函数原型:int fflush(FILE *fp);
函数作用:调用该函数将刷新缓冲区,即将输出缓冲区中所有的未写入数据被发送到 fp 指定的输出文件。如果 fp 为空指针,所有输出缓冲区都被刷新。
返回值:成功返回 0,错误返回 EOF。
创建替换使用缓冲区 setvbuf ()
函数名称:setvbuf
函数原型:int setvbuf(FILE * restrict fp, char * restrict buf, int mode, size_t size);
返回值:成功返回 0,否则返回非零值。
第二个参数指向待使用的缓冲区。如果是 NULL,则自动分配。
第三个参数为模式,有下边几种:
模式 | 描述 |
---|---|
_IOFBF | 全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。 |
_IOLBF | 行缓冲:对于输出,数据在遇到换行符或者在缓冲填满时被写入,具体视情况而定。对于输入,缓冲会在请求输入且缓冲为空时被填充,直到遇到下一个换行符。 |
_IONBF | 无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。 |
feof () 和 ferror ()
当上一次输入调用检测到文件结尾时,feof () 函数返回一个非零值,否则返回 0。
当读写出现错误,ferror () 函数返回一个非零值,否则返回 0。