/

C语言常见文件处理

每个编程语言学到文件操作、字符串操作、网络连接什么什么的就开始有各种各样的库函数需要记忆,有的比较常用还比较好记,有的遇到了却没记住,那就只能请教Google了。但考试时候不能Google,本篇旨在总结C语言中常见的文件处理操作,便于查阅和记忆。

FILE文件类型

FILE类型是一个用来表示文件的结构体

其在TC2.0编译器中的原型如下:

1
2
3
4
5
6
7
8
9
10
11
typedef struct  {
short level; /* fill/empty level of buffer */
unsigned flags; /* File status flags */
char fd; /* File descriptor */
unsigned char hold; /* Ungetc char if no buffer */
short bsize; /* Buffer size */
unsigned char *buffer; /* Data transfer buffer */
unsigned char *curp; /* Current active pointer */
unsigned istemp; /* Temporary file indicator */
short token; /* Used for validity checking */
} FILE; /* This is the FILE object */

其在VC6.0编译器中的原型如下:

1
2
3
4
5
6
7
8
9
10
11
struct _iobuf {
    char *_ptr; //文件输入的下一个位置
    int _cnt; //当前缓冲区的相对位置
    char *_base; //指基础位置(即是文件的起始位置)
    int _flag; //文件标志
    int _file; //文件的有效性验证
    int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
    int _bufsiz; //
    char *_tmpfname; //临时文件名
};
typedef struct _iobuf FILE;

在日常使用中,FILE类型常以指针形式使用。

fopen() 打开文件

该函数用于打开一个文件,函数原型如下:

1
FILE *fopen( const char * filename, const char * mode );

该函数接收两个字符串类型参数,函数将会打开一个文件,并将建立这个文件的FILE类型变量,并且返回一个指向该变量的FILE类型指针。

其中,

filename表示文件地址,数据类型为字符串,允许使用相对地址或绝对地址。例如在Windows系统下"D:\\data\\file.txt"可以用来表示地址,在Linux系统下"/mnt/test.txt"可以用来表示地址;

mode表示访问模式,数据类型为字符串,它的值可以为下列几种:

模式 描述
r 打开一个已有的文本文件,允许读取文件。
w 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。
a 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
r+ 打开一个文本文件,允许读写文件。
w+ 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。
a+ 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。
rb 打开一个已有的二进制文件,允许读取文件。
wb 打开一个二进制文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。
ab 打开一个二进制文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
rb+ 打开一个二进制文件,允许读写文件。
wb+ 打开一个二进制文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。
ab+ 打开一个二进制文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。

Example:

1
FILE *fp = fopen("/tmp/test.txt", "w+");

fclose() 关闭文件

该函数用于关闭一个文件,函数原型如下:

1
int fclose( FILE *fp );

该函数接收一个FILE类型指针变量,将会关闭这个FILE类型指针变量指向的文件,并且返回一个int类型的值。

其中

fp为一个指向所要关闭文件的FILE类型指针;

如果成功关闭文件,fclose( ) 函数返回零,如果关闭文件时发生错误,函数返回 EOF。这个函数实际上,会清空缓冲区中的数据,关闭文件,并释放用于该文件的所有内存。EOF 是一个定义在头文件 stdio.h 中的常量。

Example:

1
fclose(fp);

fputc() 将字符写入文件

该函数用于将字符输出/写入到文件中,其原型如下:

1
int fputc( int c, FILE *fp );

该函数接收一个int类型参数c和一个FILE类型指针fp,会将ASCII码为c的单个字符写入到fp指针所指向的文件中。如果写入成功,位置指针会自动后移一个字节的位置,并且返回c作为函数的返回值。如果写入失败,则返回EOF

其中,

c为要写入字符的ASCII码;

fp为指向要写入文件的FILE类型指针。

Example:

1
fputc(48,fp);

fputs() 将字符串写入文件

该函数用于将字符串输出/写入到文件中,其原型如下:

1
int fputs( const char *s, FILE *fp );

该函数接收一个char类型指针变量s和一个FILE类型指针变量fp,可以将指针s指向的字符串写入到fp所指向的文件中,如果写入成功,位置指针自动后移相应字节数,并且返回一个非负整数;否则,返回EOF

注意:指针s指向的字符串需以\0结束,但写入字符串时不会写入\0

其中,

s为char类型指针变量,指向要写入的字符串的首地址;

fp为FILE类型指针变量,指向要写入的文件。

Example:

1
fputs("hello",fp);

fprintf() 格式化写入

该函数用于格式化写入文件,其原型如下:

1
int fprintf(FILE *stream, const char *format, ...);

基本用法与printf()函数类似,接收若干个参数,第一个参数为文件指针,剩余参数与printf()函数类似,如果写入成功,则返回写入的字符总数,否则返回一个负数。

其中,

stream为指向输出文件的FILE类型指针。当该参数为stdout时该函数功能与printf()函数相同。

format是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:

specifier(说明符) 输出
c 字符
d 或 i 有符号十进制整数
e 使用 e 字符的科学科学记数法(尾数和指数)
E 使用 E 字符的科学科学记数法(尾数和指数)
f 十进制浮点数
g 自动选择 %e 或 %f 中合适的表示法
G 自动选择 %E 或 %f 中合适的表示法
o 有符号八进制
s 字符的字符串
u 无符号十进制整数
x 无符号十六进制整数
X 无符号十六进制整数(大写字母)
p 指针地址
n 无输出
% 字符
flags(标识) 描述
- 在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。
+ 强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。
(space) 如果没有写入任何符号,则在该值前面插入一个空格。
# 与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。 与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。 与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。
0 在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。
width(宽度) 描述
(number) 要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。
* 宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
.precision(精度) 描述
.number 对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。 对于 e、E 和 f 说明符:要在小数点后输出的小数位数。 对于 g 和 G 说明符:要输出的最大有效位数。 对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。 对于 c 类型:没有任何影响。 当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。
.* 精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
length(长度) 描述
h 参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。
l 参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。
L 参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。

fgetc() 从文件中读取字符

该函数用于从文件中读取一个字符,其原型如下:

1
int fgetc( FILE * fp );

该函数接收一个指向所要读取的文件的FILE类型指针,函数从fp所指向的输入文件中读取一个字符。如果读取成功,返回值是所读取的字符的ASCII码值,并且位置指针向后移动一个字节;如果发生错误则返回 EOF。

Example:

1
char ch=fgetc(fp);

fgets() 从文件中读取字符串

该函数用于从文件中读取一个字符串,其原型如下:

1
char *fgets( char *buf, int n, FILE *fp );

该函数接收一个char类型指针buf,一个int类型变量n,一个FILE类型指针fp

函数从fp所指向的文件中读取 n - 1 个字符。它会把读取的字符串复制到buf所指向的字符串,并在最后追加一个NULL字符来终止字符串。如果这个函数在读取最后一个字符之前就遇到一个换行符 ‘\n’ 或文件的末尾 EOF,则只会返回读取到的字符,包括换行符。读取成功后位置指针自动向后移动 n - 1 个字节位置。

函数返回值为char类型指针buf

其中,

buf为cahr类型指针变量,指向将要储存字符串的首地址;

n为int类型变量,表示要读取字符串长度(包括\0);

fp为FILE类型指针变量,指向要读取的文件。

fscanf() 格式化读取

该函数用于格式化读取文件,其原型如下:

1
int fscanf(FILE *stream, const char *format, ...);

基本用法与scanf()函数类似,接收若干个参数,第一个参数为文件指针,剩余参数与scacnf()函数类似,如果读取成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。

其中,

stream为指向输出文件的FILE类型指针。当该参数为stdin时该函数功能与printf()函数相同。

format是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符format 说明符
format 说明符形式为 [=%[*][width][modifiers]type=],具体讲解如下:

参数 描述
* 这是一个可选的星号,表示数据是从流 stream 中读取的,但是可以被忽视,即它不存储在对应的参数中。
width 这指定了在当前读取操作中读取的最大字符数。
modifiers 为对应的附加参数所指向的数据指定一个不同于整型(针对 d、i 和 n)、无符号整型(针对 o、u 和 x)或浮点型(针对 e、f 和 g)的大小: h :短整型(针对 d、i 和 n),或无符号短整型(针对 o、u 和 x) l :长整型(针对 d、i 和 n),或无符号长整型(针对 o、u 和 x),或双精度型(针对 e、f 和 g) L :长双精度型(针对 e、f 和 g)
type 一个字符,指定了要被读取的数据类型以及数据读取方式。具体参见下一个表格。
类型说明符 合格的输入 参数的类型
c 单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。 char *
d 十进制整数:数字前面的 + 或 - 号是可选的。 int *
e,E,f,g,G 浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4 float *
o 八进制整数。 int *
s 字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。 char *
u 无符号的十进制整数。 unsigned int *
x,X 十六进制整数。 int *

fwrite() 二进制写入

该函数用于将指定位置开始的指定字节数的内容写入到文件中,函数原型如下:

1
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);

(size_t 是在 stdio.h 和 stdlib.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。)

该函数接受4个参数,用于从内存的ptr地址开始,将连续n*size个字节的内容原样复制到fp所指向的文件中。并返回实际写入的数据块个数。

其中,

ptr为无类型指针变量,表示要输出数据在内存中的首地址;

size为一个数据块的字节数;

n为数据块的个数;

fp为FILE类型的指针,指向要写入的文件。

Example:

1
2
3
4
5
6
7
8
9
#include<stdio.h>
int main (){
FILE *fp;
char str[] = "Lakphy YES!";
fp = fopen( "file.txt" , "w" );
fwrite(str, sizeof(str) , 1, fp );
fclose(fp);
return(0);
}

fread() 二进制读取

该函数用于读取文件中从当前位置开始的指定字节数内容,然后直接存储到内存中指定起始地址的内存空间中。其函数原型如下:

1
size_t fread(void *ptr, size_t size, size_t n, FILE *fp)

该函数接受四个参数,从fp打开的文件的当前位置开始,连续读取n*size个字节的内容,存储到ptr为首地址的内存中,返回值为实际读取到内存中的数据块个数。

其中,

ptr为无类型指针,表示要输入数据在内存中的首地址;

size表示一个数据块的字节数;

n为数据块的个数;

fp为FILE类型的指针,指向要读取的文件。

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <string.h>

int main()
{
FILE *fp;
char c[] = "Lakphy YES!";
char buffer[20];

/* 打开文件用于读写 */
fp = fopen("file.txt", "w+");

/* 写入数据到文件 */
fwrite(c, strlen(c) + 1, 1, fp);

/* 查找文件的开头 */
fseek(fp, 0, SEEK_SET);

/* 读取并显示数据 */
fread(buffer, strlen(c)+1, 1, fp);
printf("%s\n", buffer);
fclose(fp);

return(0);
}

rewind() 位置指针指向文件头

该函数可以使位置指针指向文件头,函数原型如下:

1
void rewind(FILE *fp);

使fp指针指向的文件的位置指针指向文件头,同时清除和文件流相关的错误和EOF标记,无返回值。

fseek() 改变文件位置指针

该函数可以改变位置指针,其原型如下:

1
int fseek(FILE *fp, long int offset, int from);

该函数可以将文件位置从from开始移动offset个字节。执行成功返回0,不成功返回非零值。

其中,

fp为文件指针;

offset为移动的字节数,当其为正数时表示向末尾移动,负数表示向前移动,且必须为长整形数;

from为起始位置,他的取值如下:

常量 等效数字 描述
SEEK_SET 0 文件的开头
SEEK_CUR 1 文件指针的当前位置
SEEK_END 2 文件的末尾

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

int main ()
{
FILE *fp;
fp = fopen("file.txt","w+");
fputs("Lakphy YES!", fp);
fseek( fp, 7, SEEK_SET );
fputs(" C Programming Langauge", fp);
fclose(fp);

return(0);
}

ftell() 获取文件位置指针相对于文件头的位置

该函数用于获取文件位置指针相对于文件头的位置,原型如下:

1
long int ftell(FILE *fp);

fp为文件指针,返回位置指针相对于文件头的偏移字节数,如果出错则返回-1L

fflush() 刷新流 stream 的输出缓冲区

通俗讲就是更新对文件的修改,其函数原型如下:

1
int fflush(FILE *fp);

fp为文件指针。如果成功,该函数返回零值。如果发生错误,则返回 EOF,且设置错误标识符(即 feof)。

feof() 测试给定流 stream 的文件结束标识符

该函数用于检测文件的位置指针是否到达文件末尾,其原型如下:

1
int feof(FILE *stream);

fp为文件指针。到达文件末尾时返回非零值,否则返回0。

freopen()

该函数用于把一个新的文件名 filename 与给定的打开的流 stream 关联,同时关闭流中的旧文件。通常用于将输入输出重定向到文件。其原型如下:

1
FILE *freopen(const char *filename, const char *mode, FILE *stream);

filename字符串包含了要打开文件的名称;

stream是指向 FILE 对象的指针,该 FILE 对象标识了要被重新打开的流。当其为stdout时为将输出重定向到文件,当其为stdin时为重定向输入到文件。

mode为字符串,表示文件访问模式,与fopen用法一样。

返回值:如果文件成功打开,则函数返回一个指针,指向用于标识流的对象。否则,返回空指针。

Example:

1
fp = freopen("file.txt", "w+", stdout);

remove() 删除文件

该函数用于删除给定的文件名 filename,以便它不再被访问。其原型如下:

1
int remove(const char *filename);

filename表示文件地址,数据类型为字符串,允许使用相对地址或绝对地址。例如在Windows系统下"D:\\data\\file.txt"可以用来表示地址,在Linux系统下"/mnt/test.txt"可以用来表示地址.

如果成功,则返回零。如果错误,则返回 -1,并设置 errno。

rename() 重命名/移动文件

该函数用于把 old_filename 所指向的文件名改为 new_filename。可以实现文件重命名/移动。其原型如下:

1
int rename(const char *old_filename, const char *new_filename);

其中,

old_filename为要重命名的文件名;

new_filename为新的文件名。

如果成功,则返回零。如果错误,则返回 -1,并设置 errno。