C语言入门小册子
文件I/O库函数与控制台I/O函数非常相似。实际上,大多数控制台I/O函数可以被视为文件I/O函数的特殊情况。库函数包括:
fopen()
:创建或打开文件进行读写。fclose()
:在读写操作后关闭文件。fseek()
:定位文件中的特定位置。rewind()
:将文件指针重置到文件开头并保持文件打开。rename()
:重命名文件。remove()
:删除文件。fprintf()
:格式化写入文件。fscanf()
:格式化读取文件。fwrite()
:非格式化写入文件。fread()
:非格式化读取文件。putc()
:向文件写入一个字节。getc()
:从文件读取一个字节。fputs()
:向文件写入一个字符串。fgets()
:从文件读取一个字符串。
所有这些库函数依赖于stdio.h
头文件中的定义,因此需要声明:
#include <stdio.h>
C语言文档通常将这些函数称为执行“流I/O”而不是“文件I/O”。之所以有这个区别,是因为这些函数同样可以处理通过调制解调器传输的数据,而不仅仅是文件,因此使用了更通用的术语“数据流”而不是“文件”。然而,为了简便起见,本文件仍然使用“文件”这一术语。
文件I/O函数
fopen()
函数用于打开并(如果需要)创建文件。其语法如下:
<file pointer> = fopen(<filename>, <access mode>);
fopen()
函数返回一个“文件指针”,声明如下:
FILE *<file pointer>;
如果发生错误,文件指针将返回NULL
,NULL
在stdio.h
中定义。access
mode
(访问模式)有以下几种:
r
:以只读模式打开文件。w
:以写入模式打开并清空(或创建)文件。a
:以追加模式打开(或创建)文件,写入内容追加到文件末尾。r+
:以读写模式打开文件。w+
:以读写模式打开并清空(或创建)文件。a+
:以读写模式打开文件并追加内容。
filename
只是一个字符串,表示文件名。
通常,使用相同的语句来与文件或标准I/O进行通信是有用的。为此,stdio.h
头文件中包括了预定义的文件指针,分别为stdin
和stdout
。不需要对它们调用fopen()
,可以直接将它们分配给文件指针:
fpin = stdin;
fpout = stdout;
随后任何文件I/O操作都不会知道这是标准输入或标准输出。
关闭文件
fclose()
函数用于关闭由文件指针参数指定的文件。它的语法是:
fclose(fp);
定位文件
fseek()
函数允许选择文件中的字节位置进行读写。它的语法是:
fseek(<file_pointer>, <offset>, <origin>);
offset
是一个long
类型,指定文件中的偏移量(单位:字节)。origin
是一个int
类型,表示文件位置的起始点,它有以下三种标准值,在stdio.h
中定义:
SEEK_SET
:文件开头。SEEK_CUR
:当前位置。SEEK_END
:文件末尾。
fseek()
函数成功时返回0,失败时返回非零值。
重置文件、重命名文件和删除文件
rewind()
、rename()
和remove()
函数的使用非常简单:
-
rewind()
函数将打开的文件重置到文件开头,并保持文件打开。语法是:rewind(<file_pointer>);
-
rename()
函数用于更改文件名:rename(<old_file_name_string>, <new_file_name_string>);
-
remove()
函数用于删除文件:remove(<file_name_string>);
格式化输出到文件
fprintf()
函数允许将格式化的ASCII数据输出到文件,语法是:
fprintf(<file pointer>, <string>, <variable list>);
fprintf()
函数的语法与printf()
相同,唯一的区别是多了一个文件指针参数。例如,在以下程序中,fprintf()
调用将格式化输出数据到文件:
/* fprpi.c */
#include <stdio.h>
void main()
{
int n1 = 16;
float n2 = 3.141592654f;
FILE *fp;
fp = fopen("data", "w");
fprintf(fp, " %d %f", n1, n2);
fclose(fp);
}
该程序将存储以下ASCII数据:
16 3.14159
格式化代码与printf()
相同:
%d
:十进制整数%ld
:长整型十进制整数%c
:字符%s
:字符串%e
:科学记数法表示的浮点数%f
:十进制表示的浮点数%g
:根据需要选择%e
或%f
%u
:无符号十进制整数%o
:无符号八进制整数%x
:无符号十六进制整数
还可以使用字段宽度说明符。fprintf()
函数返回写入文件的字符数,或者在出现错误时返回负数。
fscanf()
函数与fprintf()
的关系就像scanf()
与printf()
的关系:它将格式化的ASCII数据读取到一个变量列表中。其语法如下:
fscanf(<file pointer>, <string>, <variable list>);
然而,string
只包含格式代码,没有文本内容,variable
list
则包含变量的地址,而不是变量本身。例如,下面的程序读取了上一个例子中通过fprintf()
存储的两个数字:
/* frdata.c */
#include <stdio.h>
void main()
{
int n1;
float n2;
FILE *fp;
fp = fopen("data", "r");
fscanf(fp, "%d %f", &n1, &n2);
printf("%d %f", n1, n2);
fclose(fp);
}
fscanf()
函数使用与fprintf()
相同的格式代码,且有一些常见的例外:
- 没有
%g
格式代码。 %f
和%e
格式代码表现一致。- 有一个
%h
格式代码用于读取短整型整数。 - 当然,也可以使用数字修饰符。
fscanf()
函数返回它成功读取的项目数,如果遇到文件末尾或错误,则返回EOF
(一个int
类型)。
以下程序展示了fprintf()
和fscanf()
的使用:
/* fprsc.c */
#include <stdio.h>
void main()
{
int ctr, i[3], n1 = 16, n2 = 256;
float f[4], n3 = 3.141592654f;
FILE *fp;
fp = fopen("data", "w+");
/* 写入数据:十进制整数格式
十进制、八进制、十六进制整数格式
浮点数格式 */
fprintf(fp, "%d %10d %-10d \n", n1, n1, n1);
fprintf(fp, "%d %o %x \n", n2, n2, n2);
fprintf(fp, "%f %10.10f %e %5.4e \n", n3, n3, n3, n3);
/* 重置文件指针。 */
rewind(fp);
/* 读取数据。 */
puts("");
fscanf(fp, "%d %d %d", &i[0], &i[1], &i[2]);
printf(" %d\t%d\t%d\n", i[0], i[1], i[2]);
fscanf(fp, "%d %o %x", &i[0], &i[1], &i[2]);
printf(" %d\t%d\t%d\n", i[0], i[1], i[2]);
fscanf(fp, "%f %f %f %f", &f[0], &f[1], &f[2], &f[3]);
printf(" %f\t%f\t%f\t%f\n", f[0], f[1], f[2], f[3]);
fclose(fp);
}
该程序生成以下输出:
16 16 16
256 256 256
3.141593 3.141593 3.141593 3.141600
fwrite()
与fread()
fwrite()
和fread()
函数用于二进制文件I/O。fwrite()
的语法如下:
fwrite(<array_pointer>, <element_size>, <count>, <file_pointer>);
array_pointer
的类型是void
,因此数组可以是任何类型。element_size
和count
分别表示每个数组元素的字节数和数组中元素的数量,它们的类型是size_t
,即与unsigned
int
等价。
fread()
函数的语法类似:
fread(<array_pointer>, <element_size>, <count>, <file_pointer>);
fread()
函数返回它实际读取的项目数。
以下程序将一个数据数组存储到文件中,然后使用fwrite()
和fread()
读取回来:
/* fwrrd.c */
#include <stdio.h>
#include <math.h>
#define SIZE 20
void main()
{
int n;
float d[SIZE];
FILE *fp;
for (n = 0; n < SIZE; ++n) /* 填充数组,计算平方根。 */
{
d[n] = (float)sqrt((double)n);
}
fp = fopen("data", "w+"); /* 打开文件。 */
fwrite(d, sizeof(float), SIZE, fp); /* 将数据写入文件。 */
rewind(fp); /* 重置文件指针。 */
fread(d, sizeof(float), SIZE, fp); /* 读取数据。 */
for (n = 0; n < SIZE; ++n) /* 打印数组。 */
{
printf("%d: %7.3f\n", n, d[n]);
}
fclose(fp); /* 关闭文件。 */
}
字符操作:putc()
与getc()
putc()
函数用于向打开的文件写入一个字符。其语法如下:
putc(<character>, <file pointer>);
getc()
函数用于从打开的文件中读取一个字符。其语法如下:
<character variable> = getc(<file pointer>);
getc()
函数在发生错误时返回EOF
。控制台I/O函数putchar()
和getchar()
实际上是putc()
和getc()
的特殊情况,它们默认使用标准输出和标准输入。
写入与读取字符串:fputs()
与fgets()
fputs()
函数将一个字符串写入文件。其语法是:
fputs(<string / character array>, <file pointer>);
如果发生错误,fputs()
函数将返回EOF
。例如:
fputs("This is a test", fptr);
fgets()
函数从文件中读取一个字符串。其语法是:
fgets(<string>, <max_string_length>, <file_pointer>);
fgets()
函数会读取字符串,直到遇到换行符或读取到<string_length-1>
个字符为止。发生错误时,它将返回NULL
。
以下示例程序通过fgets()
和fputs()
将一个文件的内容复制到另一个文件:
/* fcopy.c */
#include <stdio.h>
#define MAX 256
void main()
{
FILE *src, *dst;
char b[MAX];
/* 尝试打开源文件和目标文件。 */
if ((src = fopen("infile.txt", "r")) == NULL)
{
puts("Can't open input file.");
exit();
}
if ((dst = fopen("outfile.txt", "w")) == NULL)
{
puts("Can't open output file.");
fclose(src);
exit();
}
/* 将一个文件内容复制到另一个文件。 */
while ((fgets(b, MAX, src)) != NULL)
{
fputs(b, dst);
}
/* 完成,关闭文件。 */
fclose(src);
fclose(dst);
}
这段程序打开一个文件并将其内容复制到另一个文件。