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