跳至内容

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 );
   }

华夏公益教科书