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);
}
这段程序打开一个文件并将其内容复制到另一个文件。