C 语言入门/C 文件 I/O 通过库函数
文件 I/O 库函数非常类似于控制台 I/O 函数。事实上,大多数控制台 I/O 函数可以被视为文件 I/O 函数的特殊情况。库函数包括
fopen() Create or open a file for reading or writing. fclose() Close a file after reading or writing it. fseek() Seek to a certain location in a file. rewind() Rewind a file back to its beginning and leave it open. rename() Rename a file. remove() Delete a file. fprintf() Formatted write. fscanf() Formatted read. fwrite() Unformatted write. fread() Unformatted read. putc() Write a single byte to a file. getc() Read a single byte from a file. fputs() Write a string to a file. fgets() Read a string from a file.
所有这些库函数都依赖于在“stdio.h”头文件中定义的定义,因此需要以下声明
#include <stdio.h>
C 文档通常将这些函数称为执行“流 I/O”,而不是“文件 I/O”。区别在于,它们也可以处理通过调制解调器传输的数据,而不是文件,因此更通用的术语“数据流”而不是“文件”被使用。但是,为了简单起见,在本文件中我们将使用“文件”术语。
“fopen()”函数打开并根据需要创建文件。其语法为
<file pointer> = fopen( <filename>, <access mode> );
“fopen()”函数返回一个“文件指针”,声明如下
FILE *<file pointer>;
如果发生错误,文件指针将返回值为 NULL,在“stdio.h”中定义。 “访问模式”定义如下
r Open for reading. w Open and wipe (or create) for writing. a Append -- open (or create) to write to end of file. r+ Open a file for reading and writing. w+ Open and wipe (or create) for reading and writing. a+ Open a file for reading and appending.
“文件名”只是一串字符。
通常使用相同的语句与文件或标准 I/O 进行通信。出于这个原因,“stdio.h”头文件包含具有名称“stdin”和“stdout”的预定义文件指针。无需对它们执行“fopen()”——它们可以被直接分配给文件指针
fpin = stdin; fpout = stdout;
——之后的任何文件 I/O 函数都不会知道区别。
“fclose()”函数只关闭由其文件指针参数给定的文件。其语法为
fclose( fp );
“fseek()”函数调用允许选择文件中的字节位置以进行读写。其语法为
fseek( <file_pointer>, <offset>, <origin> );
偏移量为“long”类型,并指定文件中的偏移量(以字节为单位)。“origin”为“int”类型,是“stdio.h”中定义的三个标准值之一
SEEK_SET Start of file. SEEK_CUR Current location. SEEK_END End of file.
“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 decimal integer %ld long decimal integer %c character %s string %e floating-point number in exponential notation %f floating-point number in decimal notation %g use %e and %f, whichever is shorter %u unsigned decimal integer %o unsigned octal integer %x unsigned hex integer
字段宽度说明符也可以使用。“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+" ); /* Write data in: decimal integer formats decimal, octal, hex integer formats floating-point formats */ 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 file. */ rewind( fp ); /* Read back data. */ 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()”函数用于二进制文件 I/O。“fwrite()”的语法如下
fwrite( <array_pointer>, <element_size>, <count>, <file_pointer> );
数组指针为“void”类型,因此数组可以为任何类型。元素大小和计数(给出每个数组元素中的字节数和数组中的元素数)为“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 ) /* Fill array with roots. */ { d[n] = (float)sqrt( (double)n ); } fp = fopen( "data", "w+" ); /* Open file. */ fwrite( d, sizeof( float ), SIZE, fp ); /* Write it to file. */ rewind( fp ); /* Rewind file. */ fread( d, sizeof( float ), SIZE, fp ); /* Read back data. */ for( n = 0; n < SIZE; ++n ) /* Print array. */ { printf( "%d: %7.3f\n", n, d[n] ); } fclose( fp ); /* Close file. */ }
“putc()”函数用于将单个字符写入打开的文件。其语法为
putc( <character>, <file pointer> );
“getc()”函数类似地从打开的文件中获取单个字符。其语法为
<character variable> = getc( <file pointer> );
“getc()”函数在发生错误时返回“EOF”。控制台 I/O 函数“putchar()”和“getchar()”实际上只是使用标准输出和输入的“putc()”和“getc()”的特殊情况。
“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]; /* Try to open source and destination files. */ 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(); } /* Copy one file to the next. */ while( ( fgets( b, MAX, src ) ) != NULL ) { fputs( b, dst ); } /* All done, close up shop. */ fclose( src ); fclose( dst ); }