IO基礎知識與概念

藍桉未遇釋槐鳥發表於2024-05-12

什麼是 IO

在計算機作業系統中,所謂的I/O就是 輸入(Input)和輸出(Output),也可以理解為讀(Read)和寫(Write)

IO操作會涉及到使用者空間和核心空間的轉換,先理解以下規則:

  • 記憶體空間分為使用者空間和核心空間,也稱為使用者緩衝區和核心緩衝區;
  • 使用者的應用程式不能直接操作核心空間,需要將資料從核心空間複製到使用者空間才能使用;
  • 無論是read操作,還是write操作,都只能在核心空間裡執行;

標準IO與系統IO

    • 系統IO:不帶緩衝機制,系統IO可以操作普通檔案與驅動檔案
    • 標準IO:帶緩衝機制,標準IO只可以操作普通檔案。提供多種的格式的輸入輸出如(字串、整形......)
    • 標準IO使用連結串列管理返回值(FILE型別的指標)
    • 而系統IO使用順序表管理返回值(int型別的下標)
    • 系統IO:由作業系統直接提供的介面函式
    • 標準IO:由標準C庫(第三方庫)提供的介面函式(透過封裝作業系統提供的系統IO,再給使用者使用)
  1. 無論是標準IO還是系統IO都會提前在自身的管理結構中先後開啟stdin,stdout,stderr

  2. 標準IO=系統IO+緩衝區
    image

緩衝的作用與重新整理條件

作用:在進行資料的讀寫的過程中,先不把資料直接寫入或者讀入裝置中,而是寫或者讀入記憶體空間,當滿足一定條件時候,將該空間的檔案寫入檔案或裝置中。這樣可以減少作業系統呼叫驅動程式或檔案的次數,提高讀寫的速度,和程式碼的效率。因為每一次系統呼叫的過程都是很浪費系統資源的。

重新整理條件:

  • 緩衝區已滿
  • 強制重新整理
  • 程式結束
  • 關閉檔案

檔案開啟

標準IO

FILE *fopen(const char *filename, const char *mode)
標頭檔案 #include<stdio.h>
引數
filename 字串,表示要開啟的檔名稱
mode 字串,表示檔案的訪問模式。
選項
r 開啟一個用於讀取的檔案。該檔案必須存在。
w 建立一個用於寫入的空檔案。如果檔名稱與已存在的檔案相同,則會刪除已有檔案的內容,檔案被視為一個新的空檔案。
a 追加到一個檔案。寫操作向檔案末尾追加資料。如果檔案不存在,則建立檔案。
r+ 開啟一個用於更新的檔案,可讀取也可寫入。該檔案必須存在。
w+ 建立一個用於讀寫的空檔案。如果檔名稱與已存在的檔案相同,則會刪除已有檔案的內容,檔案被視為一個新的空檔案。
a+ 開啟一個用於讀取和追加的檔案。
上述後+b 以二進位制的方式開啟(不加則預設以文字形式開啟)
返回值
成功返回檔案指標(FILE *)
失敗返回NULL

系統IO

int open(const char * pathname, int flags);
int open(const char * pathname, int flags, mode_t mode);
標頭檔案 #include<stdio.h>
#include<fcntl.h>//在centos6.0中只要此標頭檔案就可以
#include<sys/types.h>
#include<stdio.h>
#incldue<sys/stat.h>
引數
pathname 要開啟或建立的目標檔案。
flags 開啟檔案時,可以傳入多個引數選項,用下面的
一個或者多個常量進行“或”運算,構成falgs。
選項
O_RDONLY 以只讀方式開啟檔案
O_WRONLY 以只寫方式開啟檔案
O_RDWR 以可讀寫方式開啟檔案。 上述三種旗標是互斥的, 也就是不可同時使用, 但可與下列的旗標利用OR
O_CREAT 若欲開啟的檔案不存在則自動建立該檔案
O_EXCL 如果O_CREAT 也被設定, 此指令會去檢查檔案是否存在。 檔案若不存在則建立該檔案, 否則將導致開啟檔案錯誤。
O_APPEND 當讀寫檔案時會從檔案尾開始移動, 也就是所寫入的資料會以附加的方式加入到檔案後面.
返回值
成功返回檔案識別符號(int)
失敗返回-1

資料獲取

標準IO

共有三類獲取方式,六個函式介面

1. 按字元獲取

int fgetc(FILE *stream)
int getc(FILE *stream)
int getchar(void)
標頭檔案 #include<stdio.h>
引數
stream 這是指向 FILE 物件的指標,該 FILE 物件標識了要在上面執行操作的流。
返回值
成功 讀取到的單個字元
失敗 EOF(End of File)

2. 按行獲取

char *fgets(char *str, int n, FILE *stream)
char *gets(char *s)
標頭檔案 #include<stdio.h>
引數
str 這是指向一個字元陣列的指標,該陣列儲存了要讀取的字串。
n 這是要讀取的最大字元數(包括最後的空字元)。通常是使用以 str 傳遞的陣列長度。
stream 這是指向 FILE 物件的指標,該 FILE 物件標識了要在上面執行操作的流。
返回值
成功 返回相同的 str 引數
失敗/到達檔案末尾/沒有讀取到任何字元 返回一個空指標

3. 按塊獲取

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
標頭檔案 #include<stdio.h>
引數
ptr 這是指向帶有最小尺寸 size*nmemb 位元組的記憶體塊的指標。
size 這是要讀取的每個元素的大小,以位元組為單位。
nmemb 這是元素的個數,每個元素的大小為 size 位元組。
stream 這是指向 FILE 物件的指標,該 FILE 物件標識了要在上面執行操作的流。
返回值
成功 以 size_t 物件返回,size_t 物件是一個整型資料型別。
失敗/到達檔案末尾 總數與 nmemb 引數不同

系統IO

ssize_t read(int fd, void * buf, size_t count);
標頭檔案 #include<unistd.h>
引數
fd 這是指向 FILE 物件的指標,該 FILE 物件標識了要在上面執行操作的流。
buf 這是指向記憶體塊的指標。
count 這是元素的個數,每個元素的大小為 1 位元組。
返回值
成功 返回實際讀到的位元組數量
到達檔案末尾 返回位元組數<=count
失敗 -1

資料寫入

標準IO

一共三類寫入方式,六種介面

1. 按字元寫入

int fputc(int c,FILE *stream)
int putc(int c,FILE *stream)
int putchar(int c)
標頭檔案 #include<stdio.h>
引數
c 這是y要寫入的字元。
stream 這是指向 FILE 物件的指標,該 FILE 物件標識了要在上面執行操作的流。
返回值
成功 非負整數
失敗 EOF

2. 按行寫入

char *fputs(const char *str, FILE *stream)
char *puts(const char *str)
標頭檔案 #include<stdio.h>
引數
str 這是要寫入的字串。
stream 這是指向 FILE 物件的指標,該 FILE 物件標識了要在上面執行操作的流。
返回值
成功 非負整數
失敗 EOF

3. 按塊寫入

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
標頭檔案 #include<stdio.h>
引數
ptr 這是指向帶有最小尺寸 size*nmemb 位元組的記憶體塊的指標。
size 這是要讀取的每個元素的大小,以位元組為單位。
nmemb 這是元素的個數,每個元素的大小為 size 位元組。
stream 這是指向 FILE 物件的指標,該 FILE 物件標識了要在上面執行操作的流。
返回值
成功 返回寫入的資料塊個數=nmemb
失敗/到達檔案末尾 返回值 < nmemb

系統IO

int write(int handle,void *buf,int len);
標頭檔案 #include<io.h>
引數
handle 這是要獲取檔案指標的檔案識別符號
buf 這是要寫入的內容。
len 這是要寫入檔案的長度。
返回值
成功 返回寫入的資料塊個數=nmemb
失敗/到達檔案末尾 返回值 < nmemb

檔案關閉

標準IO

int fclose(FILE *stream)
標頭檔案 #include<stdio.h>
引數
stream 這是指向 FILE 物件的指標,該 FILE 物件指定了要被關閉的流。
返回值
成功 返回0
失敗 返回EOF

系統IO

int close(int fd)
標頭檔案 #include<unistd.h>
引數
fd 是需要關閉的檔案描述符。
返回值
成功 返回0
失敗 返回-1,並設定errno

檔案游標

標準IO

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

標頭檔案 #include<stdio.h>
引數
stream 這是指向 FILE 物件的指標,該 FILE 物件指定了要被關閉的流。
offset 這是相對 whence 的偏移量,以位元組為單位。
whence 這是表示開始新增偏移 offset 的位置。一般指定為下列常量之一
SEEK_SET 檔案的開頭
SEEK_CUR 檔案指標的當前位置
SEEK_END 檔案的末尾
返回值
成功 返回0
失敗 返回非0

系統IO

off_t lseek(int fd, off_t offset, int whence);
標頭檔案
#include <sys/types.h>
#include <unistd.h>
引數
fd 這是檔案描述符。。
offset 這是相對 whence 的偏移量,以位元組為單位。
whence 這是表示開始新增偏移 offset 的位置。一般指定為下列常量之一
SEEK_SET 檔案的開頭
SEEK_CUR 檔案指標的當前位置
SEEK_END 檔案的末尾
返回值
成功 返回從檔案頭部開始算起到當前讀寫位置的偏移量
失敗 返回-1,並設定errno