Linux:基礎IO(cIO庫函式詳細介紹)(IO系統呼叫介面詳細介紹)(兩者關係:檔案描述符和檔案指標)
目錄
fput:把字串寫入到指定的流( stream) 中,但不包括空字元。
c系統中的庫函式:
在c中,檔案操作都是由庫函式實現的,標頭檔案都為<stdio.h>主要是分為讀和寫兩張操作
fopen:開啟檔案
函式原型: FILE * fopen(const char *path,cost char *mode)
作用:開啟一個檔案,返回指向該檔案的指標
引數說明:
第一個引數為開啟檔案的路徑及檔名
第二個引數表示開啟的方式
開啟方式:
- r:只讀方式開啟,檔案必須存在
- r+:可讀寫,必須存在
- rb+:開啟二進位制檔案,可以讀寫
- rt+:開啟文字檔案,可讀寫
- w:只寫,檔案存在則檔案長度清0,檔案不存在則建立該檔案
- w+:可讀寫,檔案存在則檔案長度清0,檔案不存在則建立該檔案
- 上述如r、w、a在其後都可以加一個b,表示以二進位制形式開啟檔案
返回值:檔案打開了返回一個指向該開啟檔案的指標(FILE結構),開啟失敗返回NULL,並且將錯誤程式碼存在errno
fclose:關閉檔案
函式原型:int fclose(FILE *stream)
功能:關閉一個檔案流,使用fclose就可以把緩衝區內最後剩餘的資料輸出到磁碟檔案中,並釋放檔案指標和有關的緩衝區
fwrite:向檔案寫入一個數據塊
函式原型:size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
返回值:返回實際寫入的資料塊數目
引數說明:
- buffer:是一個指標,對fwrite來說,是要獲取資料的地址;
- size:要寫入內容的單位元組數;
- count:要進行寫入size位元組的個數;
- stream:目標檔案指標;
返回值:實際寫入的資料項個數count。
fread:讀寫
函式原型: size_t fread(void* buff,size_t size,size_t count,FILE* stream)
引數說明: 從檔案中讀入資料到指定的地址中
- buff: 接收資料的的指標(buff),就是資料的儲存地址
- size:單個元素的大小(單位為位元組)
- count: 引數的元素個數
- stream:資料的檔案指標,指向檔案內部資料
返回值:讀取的總資料元素個數
fprintf:格式化輸出到一個流/檔案中
函式原型: int fprintf( FILE *stream, const char *format, [ argument ]...)
fprintf()函式根據指定的格式(format)向輸出流(stream)寫入資料(argument)
引數說明:
- stream:檔案指標
- format:輸出格式
- 第三個:附加引數列表
規定符:
- %d, %i 十進位制有符號整數
- %u 十進位制無符號整數
- %f 浮點數
- %s 字串
- %c 單個字元
- %p指標的值
fseek:移動/跳轉 到當前 讀取/寫入位置
函式原型:int fseek(FILE *stream,long offset,int framewhere)
作用:重定位檔案內部的指標
引數是說明:
- 第一個為檔案指標,
- 第二個是指標的偏移量,
- 第三個是指標偏移起始位置
返回值:重定位成功返回0,否則返回非零值
需要注意的是該函式不是重定位檔案指標,而是重定位檔案內部的指標,讓指向檔案內部資料的指標移到檔案中我們感興趣的資料上,重定位主要是這個目的。
說明:執行成功,則stream指向以fromwhere為基準,偏移offset個位元組的位置。執行失敗(比方說offset偏移的位置超出了檔案大小),則保留原來stream的位置不變
起始點有三個常量值:
- SEEK_SET 0 檔案開頭
- SEEK_CUR 1 檔案當前位置
- SEEK_END 2 檔案末尾
fgets:獲取字串
函式原型:char *fgets(char *str, int num, FILE *fp)
返回值:返回第一個引數buf
引數說明:
- str: 儲存從檔案讀取出來的字串
- fp: 待讀檔案的檔案指標
- num: 表示從檔案中讀出的字串不超過 n-1個字元。在讀入的最後一個字元後加上串結束標誌'\0'
fput:把字串寫入到指定的流( stream) 中,但不包括空字元。
函式原型: int fputs(char * str,FILE * stream)
引數說明:
str:這是一個數組,包含了要寫入的以空字元終止的字元序列。
stream:指向 FILE 物件的指標,該 FILE 物件標識了要被寫入字串的流
返回值:該函式返回一個非負值,如果發生錯誤則返回 EOF(-1)。
ftell:用於得到檔案位置指標當前位置相對於檔案首的偏移位元組數
函式原型:long ftell(FILE *stream)
函式功能:
使用fseek函式後再呼叫函式ftell()就能非常容易地確定檔案的當前位置。
rewind改變內部指標
函式原型: void rewind(FILE *stream);
函式功能:將檔案內部的指標重新指向一個流的開頭系統呼叫
注意: 不是檔案指標而是檔案內部的位置指標,隨著對檔案的讀寫檔案的位置指標(指向當前讀寫位元組)向後移動。而檔案指標是指向整個檔案,如果不重新賦值檔案指標不會改變。
程式碼演示
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* fp = fopen("test","w");
if(!fp)
{
perror("fopen");
return -1;
}
const char* tmp = "WJF-handsome\n";
fwrite(tmp ,1,strlen(tmp),fp);
fclose(fp);
return 0;
}
輸出方式
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
const char* tmp = "hello f\n";
fwrite(tmp,strlen(tmp),1,stdout);
printf("hello p\n");
fprintf(stdout,"hello fp\n");
return 0;
}
IO系統呼叫介面
標頭檔案:#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
open
函式原型:
int open(const char * pathname, int flags);
int open(const char * pathname, int flags, mode_t mode);
引數說明:
pathname:開啟路徑
flags:開啟方式
O_RDONLY 以只讀方式開啟檔案
O_WRONLY 以只寫方式開啟檔案
O_RDWR 以可讀寫方式開啟檔案.
上述三種旗標是互斥的, 也就是不可同時使用, 但可與下列的旗標利用OR(|)運算子組合.
- O_CREAT 若欲開啟的檔案不存在則自動建立該檔案.
- O_EXCL 如果O_CREAT 也被設定, 此指令會去檢查檔案是否存在. 檔案若不存在則建立該檔案, 否則將導致開啟檔案錯誤. 此外, 若
- O_CREAT 與O_EXCL 同時設定, 並且欲開啟的檔案為符號連線, 則會開啟檔案失敗.
- O_NOCTTY 如果欲開啟的檔案為終端機裝置時, 則不會將該終端機當成程序控制終端機.
- O_TRUNC 若檔案存在並且以可寫的方式開啟時, 此旗標會令檔案長度清為0, 而原來存於該檔案的資料也會消失.
- O_APPEND 當讀寫檔案時會從檔案尾開始移動, 也就是所寫入的資料會以附加的方式加入到檔案後面.
- O_NONBLOCK 以不可阻斷的方式開啟檔案, 也就是無論有無資料讀取或等待, 都會立即返回程序之中.
- O_NDELAY 同O_NONBLOCK.
- O_SYNC 以同步的方式開啟檔案.
- O_NOFOLLOW 如果引數pathname 所指的檔案為一符號連線, 則會令開啟檔案失敗.
- O_DIRECTORY 如果引數pathname 所指的檔案並非為一目錄, 則會令開啟檔案失敗
mode:許可權
引數mode 則有下列數種組合, 只有在建立新檔案時才會生效, 此外真正建檔案時的許可權會受到umask 值所影響, 因此該檔案許可權應該為 (mode-umaks).
- S_IRWXU00700 許可權, 代表該檔案所有者具有可讀、可寫及可執行的許可權.
- S_IRUSR 或S_IREAD, 00400 許可權, 代表該檔案所有者具有可讀取的許可權.
- S_IWUSR 或S_IWRITE, 00200 許可權, 代表該檔案所有者具有可寫入的許可權.
- S_IXUSR 或S_IEXEC, 00100 許可權, 代表該檔案所有者具有可執行的許可權.
- S_IRWXG 00070 許可權, 代表該檔案使用者組具有可讀、可寫及可執行的許可權.
- S_IRGRP 00040 許可權, 代表該檔案使用者組具有可讀的許可權.
- S_IWGRP 00020 許可權, 代表該檔案使用者組具有可寫入的許可權.
- S_IXGRP 00010 許可權, 代表該檔案使用者組具有可執行的許可權.
- S_IRWXO 00007 許可權, 代表其他使用者具有可讀、可寫及可執行的許可權.
- S_IROTH 00004 許可權, 代表其他使用者具有可讀的許可權
- S_IWOTH 00002 許可權, 代表其他使用者具有可寫入的許可權.
- S_IXOTH 00001 許可權, 代表其他使用者具有可執行的許可權.
返回值:若所有欲核查的許可權都通過了檢查則返回0 值, 表示成功, 只要有一個許可權被禁止則返回-1.
close
函式原型:
int close(int fildes);
作用:close系統呼叫用於“關閉”一個檔案,close呼叫終止一個檔案描述符fildes以其檔案之間的關聯。檔案描述符被釋放,並能夠重新使用。
返回值:close成功返回1,出錯返回-1
read
函式原型:
size_t read(int fildes, void *buf, size_t nbytes);
引數說明:
- fildes:檔案描述符,標識要讀取的檔案。如果為0,則從標準輸入讀資料。類似於scanf()的功能。
- *buf:緩衝區,用來儲存讀入的資料。
- nbytes:要讀取的字元數。
- 返回值:size_t返回成功讀取的字元數,它可能會小於請求的位元組數。
write
函式原型:
size_t write(int fildes, const void *buf, size_t nbytes);
引數說明:
- fildes:檔案描述符,標識了要寫入的目標檔案。例如:fildes的值為1,就像標準輸出寫資料,也就是在顯示屏上顯示資料;如果為 2 ,則想標註錯誤寫資料。
- *buf:待寫入的檔案,是一個字串指標。
- nbytes:要寫入的字元數。
- 函式返回值:size_t 返回成功寫入檔案的字元數。
lseek
函式原型:
off_t lseek(int fd, off_t offset, int whence)
引數說明:
- fd是開啟的檔案描述符
- offset是與參考偏移的位置
- whence是檔案參考的位置
它一共有三個位置
- SEEK_SET 檔案開始,如果使用此偏移,那麼檔案定位到offset的位置
- SEEK_CUR 檔案讀寫指標的當前位置
- SEEK_END 檔案結尾
lseek返回值是檔案讀寫指標移動之後的位置,-1表示失敗
a,取得檔案當前偏移位置可以如下: f_offset = lseek(fd, 0, SEEK_CUR);
b,檔案大小可以通過下面: f_len = lseek(fd, 0, SEEK_END);
c,使用lseek函式移動好讀寫指標之後,使用read,write即可往檔案裡面讀寫資料。
程式碼演示:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
int fd = open("test",O_RDONLY);
if(fd < 0)
{
perror("open");
return -1;
}
char* buf[1024];
ssize_t s = read(fd,buf,12);//1從哪讀2放在那3讀多少
printf("%s\n",buf);
close(fd);
return 0;
}
系統呼叫和庫函式的關係
兩者關係
f開頭的函式,都是對系統呼叫的封裝,方便二次開發
檔案描述符fd
檔案描述符實質就是一個整數,當做檔案的ID,在系統中標識檔案
一個程序要對所有開啟的檔案進行管理,先將檔案描述起來,然後組織進行管理,程序對檔案進行描述的結構叫:file(struct file)
程序使用了一個結構體來組織這些描述符,而檔案描述符就是這結構體陣列下標
Linux程序預設會開啟三個檔案描述符:
- 標準輸入0
- 標準輸出1
- 標準錯誤2
- 0,1,2一般對應的物理裝置有:鍵盤,顯示器,顯示器
stdin | stdout | stderr | FILE* | 檔案流指標 |
0 | 1 | 2 | int | 檔案描述符 |
每個程序在PCB(Process Control Block)中儲存著一份檔案描述符表,檔案描述符就是這個表的索引,每個表項都有一個指向已開啟檔案的指標。
檔案指標
C語言中使用檔案指標做為I/O的控制代碼。檔案指標指向程序使用者區中的一個被稱為FILE結構的資料結構。
FILE結構包括一個緩衝區和一個檔案描述符。(庫函式是系統呼叫的封裝,所以檔案流指標包含檔案描述符)
而檔案描述符是檔案描述符表的一個索引,因此從某種意義上說檔案指標就是控制代碼的控制代碼(在Windows系統上,檔案描述符被稱作檔案控制代碼)。
當我們開啟檔案時,作業系統在記憶體中要建立相應的資料結構來描述目標檔案,於是就有了file結構體
表示一個已經開啟的檔案物件,而程序執行open系統呼叫,所有必須要讓程序和檔案關聯起來,
每個程序都有一個*file指標,指向一張表files_struct ,這個最重要的就是包含一個指標陣列,
每個元素都是一個指向開啟檔案的指標。
所以本質上檔案描述符就是該陣列的下標,只要拿著檔案描述符,就能找到對應檔案