常用標準io

do泽發表於2024-08-10

常用標準io

目錄
  • 常用標準io
    • 標準io基本概念
    • 標準io基本API
      • 開啟檔案 fopen
        • FILE型別的指標
      • 關閉檔案fclose
      • 讀取檔案資料
        • 按字元讀取fgetc
        • 按行讀取fgets
          • 關於緩衝區
            • fflush
        • 按塊讀取fread
          • 判斷檔案已到末尾還是出錯feof/ferror
      • 寫入檔案
        • 字元寫入
        • 按行寫入
        • 按塊寫入
      • 檔案位置
        • 設定位移fseek
        • 獲取位移

標準io基本概念

​ 為滿足使用者訪問檔案的需求,提高使用者程式的可移植性,標準庫也提供了一組操作檔案的函式介面,通常被稱為標準io,標準io遵循ANSI C標準設計而來,目的是方便使用者在不同作業系統下可以呼叫通用函式來實現對檔案的讀寫訪問實際上,標準io是基於系統io設計出來的

標準io基本API

一般情況區,關閉檔案即可將標準緩衝區資料沖洗到核心緩衝區,當資料到核心緩衝區,資料則會寫入到檔案。

開啟檔案 fopen

標頭檔案

#include <stdio.h>

函式原型

FILE *fopen(const char *path,const char *mode );

成功返回檔案指標,失敗返回NULL

功能:獲取指定檔案的檔案指標

path:即將開啟的檔案

mode :

r 只讀方式開啟檔案,要求檔案必須存在
r+ 讀寫方式開啟檔案,要求檔案必須存在
w 只讀方式開啟檔案,檔案不存在會新建檔案,檔案存在會清空檔案
w+ 讀寫方式開啟檔案,檔案不存在會新建檔案,檔案存在會清空檔案
a 只寫方式開啟檔案,檔案不存在會建立檔案,檔案位置偏移量會自動定位到檔案末尾(追加方式寫資料)
a+ 讀寫方式開啟檔案,檔案不存在會建立檔案,檔案位置偏移量會自動定位到檔案末尾(追加方式寫資料)

標準io的都游標和寫游標是不同的,且可以指向不同的位置。

FILE型別的指標

FILE型別其實是一個結構體資料型別,它包含了標準 I/O 庫函式為管理檔案所需要的所有資訊,比如包括用於實際I/O 的檔案描述符、指向檔案緩衝區的指標、緩衝區的長度、當前緩衝區中的位元組數以及出錯標誌等。

閱讀stdio.h中的條件編譯選項可以發現在stdio.h中還包含了另一個標頭檔案<libio.h>,這個標頭檔案中才有關於FILE結構體型別的定義

開啟標頭檔案<libio.h>之後,可以找到關於FILE結構體型別的定義,可以發現FILE結構體型別中的成員數量很多

以看到FILE結構體型別中有一個成員是FILE型別的指標變數chain,該指標可以指向下一個被開啟檔案的檔案資訊區,也就是可以把FILE型別當做資料結構中的連結串列的結點,結點中除了可以儲存資料域之外,還可以利用指標域儲存下一個結點的地址。

使用者可以在一個程式中利用fopen函式開啟多個檔案,每次開啟一個檔案,核心就會從*堆記憶體*中申請一塊FILE結構體大小的空間用來儲存檔案的所有資訊,然後按照檔案開啟的順序把每個開啟的檔案的結構體形成一條連結串列,然後使用連結串列頭進行管理。

開啟檔案的目的無非就是對檔案進行讀寫操作,所以每次當程式執行的時候已經有三個檔案流被開啟,分別是標準輸入stdin、標準輸出stdout、標準出錯stderr,這三者在stdio.h中也是FILE指標。

關閉檔案fclose

標頭檔案

#include <stdio.h>

函式原型

int fclose (FILE *fp);

成功返回 0,失敗返回EOF;

EOF是檔案結束標誌,是一個宏定義,值為-1;

功能:關閉指定檔案並釋放資源

fp:即將關閉的檔案

關閉檔案時,核心會將檔案對應的堆記憶體從連結串列中刪除,再釋放。

使用標準IO的時候,是不可以反覆關閉相同的檔案,因為釋放已經被釋放的堆記憶體,會導致段錯誤

讀取檔案資料

使用者開啟檔案後可以從檔案中讀取資料,標準C庫中提供了多個讀取函式來滿足使用者的不同需求,這些函式大體分為三類:字元讀取(fgetc)、按行讀取(fgets)、按塊讀取(fread)。

按字元讀取fgetc

標頭檔案

include <stdio.h>

函式原型

int fgetc(FILE * stream);
int getc (FILE * stream);//功能等效與fgetc,,但透過宏定義實現
int getchar (void);

功能:獲取一個指定檔案的字元,並在讀取一個位元組後將游標位置向後移動一個位元組;

成功:返回讀到的字元的ASCII;失敗:EOF(讀到文尾或錯誤);

按行讀取fgets

透過C99標準可以知道該函式的作用是從檔案指標stream指向的檔案中讀取一行字元,並把讀取的字元儲存在指標s所指向的字串內,當讀取到n-1個字元、或者已經讀取到檔案末尾(EOF)、或者讀取到換行符’\n’時,則函式呼叫停止。

標頭檔案

#include <sys/ioctl.h>

函式原型

char * fgets(char *s,int size ,FILE *stream);
char * gets(char *s);//預設後自動從stdin 讀取檔案

成功:返回自定義緩衝區指標;

失敗:NULL(讀到文尾或錯誤);

s:自定義緩衝區指標

size :自定義緩衝區大小

stream:即將被讀取資料的檔案指標

關於緩衝區

使用者呼叫fopen開啟檔案之後,可以把資料寫入到檔案中以及從檔案中讀取資料,但是實現讀取和寫入的過程中其實核心並沒有直接操作檔案,而是在操作指向檔案的結構體指標FILE,也就是使用者寫入的資料和讀取的資料會先儲存在FILE結構體的*緩衝區*中,當使用者呼叫重新整理緩衝區的函式或者其他讀寫函式時,FILE結構體的緩衝區會被重新整理,資料才會被系統寫入檔案

每當使用標準IO的讀操作函式,試圖將資料從檔案 a.txt讀取出來時,資料都會流過標準*輸入**緩衝區*,然後再在適當的時刻沖洗(或稱重新整理,flush)到核心緩衝區,最後才真正得到資料。

緩衝區的出現其實就是由於輸入裝置和輸出裝置對於資料的讀寫速度比較慢,其實就是CPU為了降低輸入輸出次數,目的是為了提高執行效率,避免長時間的等待,所以核心就在記憶體中提供了一塊空間作為緩衝區,緩衝區也可以稱為快取(Cache),是屬於記憶體空間的一部分。

根據IO裝置的不同,可以把緩衝區分為輸入緩衝區和輸出緩衝區,同樣,根據重新整理形式的不同,可以把緩衝區分為三種:全緩衝、行緩衝、無緩衝。

全緩衝:指的是當緩衝區被填滿就立即把資料沖刷到檔案、或者在關閉檔案、讀取檔案內容以及修改緩衝區型別時也會立即把資料沖刷到檔案,一般讀寫檔案的時候會採用。

無緩衝:指的是沒有緩衝區,直接輸出,一般linux系統的標準出錯stderr就是採用無緩衝,這樣可以把錯誤資訊直接輸出。

行緩衝:指的是當緩衝區被填滿(一般緩衝區為4KB,就是4096位元組)或者緩衝區中遇到換行符’\n’時,或者在關閉檔案、讀取檔案內容以及修改緩衝區型別時也會立即把資料沖刷到檔案中,一般操作IO裝置時會採用,比如printf函式就是採用行緩衝。

全緩衝和行緩衝除了以上幾種情況外,當程式結束時緩衝區也會被重新整理,另外,也可以採用函式庫中的fflush函式手動重新整理緩衝區。

對於標準輸出stdout而言預設是採用行緩衝的,而對於標準出錯stderr而言預設是採用無緩衝的,對於普通檔案而言預設是採用全緩衝的。

fflush
/*標頭檔案:*/
#include <stdio.h>
/*函式原型*/
int fflush(FILE *stream);

按塊讀取fread

標頭檔案

#include <sys/iotcl.h>

函式原型

size_t fread (void *ptr,size_t size,size_t nmemb,FILE *stream);

成功:返回讀取的資料塊個數(等於nmemb);失敗:讀取的資料塊個數(小於nmemb或等於0)||(已達文尾或錯誤)

ptr:自定義緩衝區指標

size:資料塊大小

nmemb:資料塊個數

stream:即將被讀取資料的檔案指標

判斷檔案已到末尾還是出錯feof/ferror

標頭檔案

#include <stdio.h>

函式原型

int feof(FILE *stream);//讀到文尾時為真
int ferror(FILE *stream);//出錯時為真

寫入檔案

字元寫入

標頭檔案

#include <stdio.h>

函式原型

int fputc (int c ,FILE *stream);
int putc (int c,FILE *stream);
int putchar(int c);

成功:寫入到的字元;失敗:EOF

c:要寫入的字元

stream:寫入的檔案指標

按行寫入

標頭檔案

#include <sys/ioctl.h>

函式原型

int fputs(const char *s,FILE *stream);
int puts(const char *s);

成功:非負整數;失敗:EOF

s:自定義緩衝區指標

stream:即將被寫入資料的檔案指標

按塊寫入

標頭檔案

#include <sys/ioctl.h>

函式原型

size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);

成功:返回寫入的資料塊個數(等於nmemb);失敗:寫入的資料塊個數(小於nmemb或等於0)||(已達文尾或錯誤)

ptr:自定義緩衝區指標

size:資料塊大小

nmemb:資料塊個數

stream:即將被寫入資料的檔案指標

檔案位置

設定位移fseek

標頭檔案

#include <sys/ioctl.h>

函式原型

int fseek (FILE *stream ,long offset,int whence);

功能:設定指定檔案的當前位置偏移量

stream :需要設定位置偏移量的檔案

offset: 新位置偏移量相對基準點的位移

whence:基準點

SEEK_SET:檔案開頭

SEEK_CUR:當前位置

SEEK_END:檔案末尾

獲取位移

標頭檔案

#include <sys/ioctl.h>

函式原型

long ftell(FILE *stream);

成功:當前檔案偏移量;失敗:-1;

stream :需要返回當前檔案位置偏移量的檔案指標

相關文章