跳至內容

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

華夏公益教科書