文件I/O操做在Linux編程時是常常會使用到的一個內容,一般能夠把比較大的數據寫到一個文件中來進行存儲或者與其餘進程進行數據傳輸,這樣比寫到一個全局數組或指針參數來實現還要方便好多。linux
1.打開或建立一個文件:編寫程序時涉及內容——打開或建立文件的路徑名稱、打開文件的方式(讀|寫|執行)、訪問權限(用戶|組|其餘)、實現方式(系統調用|庫)。編程
①系統調用方式:vim
1 #include <fcntl.h> //函數原型聲明、flags定義 2 #include<sys/stat.h> //mode定義 3 int open( const char * pathname,int flags, mode_t mode);//當須要建立新的文件時才須要使用第3個參數mode
pathname:不帶路徑時默認在當前目錄下數組
flags:打開方式,經常使用選項——O_RDWR(讀寫打開)、O_RDONLY(只讀打開)、O_WRONLY(只寫打開)、O_CREAT(文件不存在時建立)、app
mode:使用O_CREAT時設置訪問權限,經常使用選項——S_IRUSR(用戶可讀)、S_IWUSR(用戶可寫)、S_IXUSR(用戶可執行)函數
返回值:成功——文件描述符(int),失敗——(-1)spa
打開一個文件操做結束以後要記得關閉文件,與其對應的函數:指針
#include<unistd.h> int close(int fd);
②庫函數方式:code
#include<stdio.h> FILE * fopen(const char * path,const char * mode);//FILE是文件流結構
path:文件路徑名,包括文件名blog
mode:打開文件的方式。注意!這個形參是指針。編程時要使用字符串的形式。經常使用設置——b:以二進制格式打開或建立文件、t:打開文本文件、r:只讀、w:只寫、+:只要有加號出現就表示可讀可寫、a:append追加的意思,往文件末尾插入,這樣就不會覆蓋掉原來的內容。根據須要進行組合設置。
返回值:成功——指向FILE文件流的指針,失敗——NULL。
與其對應的關閉函數:
#include<stdio.h> int fclose(FILE * stream);
該函數會讓緩衝區內的數據寫入文件中,並釋放系統所提供的文件資源。成功執行返回0。
2.設置文件指針的位置:文件指針是讀寫文件操做時的起始位置,直接關係到讀寫的結果。進行讀寫操做時須要明確當前文件指針所處的位置。
①系統調用方式:
#include<unistd.h> #include<sys/types.h> off_t lseek(int fildes,off_t offset ,int whence);
whence:設置文件位置時的參考點——SEEK_SET 參數offset即爲新的讀寫位置、SEEK_CUR 以目前的讀寫位置日後增長offset個位移量、SEEK_END 將讀寫位置指向文件尾後再增長offset個位移量
返回值:成功——設置成功以後的文件位置(距離文件起始位置),失敗——(-1)
②庫函數方式:
#include<stdio.h> int fseek(FILE * stream,long offset,int whence);
參數和lseek()函數如出一轍
返回值:成功——(0),失敗——(-1)
3.寫內容到文件:涉及內容——寫的位置、內容、大小等,寫完以後文件「指針」位置會跟着向後移動。
①系統調用方式:
#include<unistd.h> ssize_t write (int fd,const void * buf,size_t count);
返回值:成功——寫入的字節數,失敗——(-1)
②庫函數方式:
#include<stdio.h> size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream);
返回值:成功——寫入的字節數
4.讀出文件內容:從文件指針處,讀出count個字節數到buf指針指向的存儲區
①系統調用方式:
#include<unistd.h> ssize_t read(int fd,void * buf ,size_t count);
返回值:成功——讀出的字節數,失敗——(-1)
②庫函數方式:
#include<stdio.h> size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream);
返回值:成功——讀出的字節數
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <unistd.h> 6 7 int main() 8 { 9 int fd,ret,rdlen; 10 char tmp[10]; 11 fd = open("./myfile",O_RDWR|O_CREAT,S_IRUSR|S_IWUSR); 12 ret = chown(file_name,1000,1000); 13 if( ret<0 ) 14 printf("chown() error.\n"); 15 lseek(fd,0,SEEK_SET); 16 rdlen = read(fd,tmp,10); 17 if(rdlen<0) 18 { 19 printf("read local file error.\n"); 20 return -1; 21 } 22 return 0; 23 }
問1.爲何有系統調用方式來實現文件I/O操做還要庫函數方式?
答1.系統調用須要進行用戶空間和內核空間之間的切換,這種切換對CPU的開銷大,若是大量使用系統調用會大大下降CPU的工做效率,爲了解決這個問題因而有了庫函數方式,他是一種帶緩衝區的操做,當用戶空間緩衝區滿或者寫操做結束時,纔將用戶緩衝區的內容寫到內核緩衝區,一樣的道理,當內核緩衝區滿或寫結束時纔將內核緩衝區內容寫到文件對應的硬件平臺,如此一來就大大減小了系統調用的次數,大大提升CPU工做效率。
問2.write和fwrite函數把內容寫到文件中是以哪一種格式寫入的?爲何用軟件打開本身寫的文件時會亂碼?vim中如何以16進制格式顯示打開的二進制文件?
答2.在linux下這兩個函數都是以二進制的格式把內容寫到文件裏邊的。像Uedit軟件打開文件時他是會根據文件的後綴名來對文件進行轉格式顯示出來的,也就是說,大多狀況下咱們看到的內容和文件中實際的存儲格式是不同的。vim中若是要打開一個二進制文件要加「-b」選項,打開後在命令模式下輸入「:%!xxd」便可讓二進制文件內容以16進制格式來顯示,16進制更容易讓咱們從中獲取數據的信息。
問3.如何建立一批文件,要求文件名具備某種格式?
答3.使用sprint()函數對文件名進行格式化處理。
問4.如何修改文件的全部者?
答4.發現程序執行第一遍程序時能夠成功執行,第二次運行出錯,原來是文件權限問題,不知爲毛默認建立的文件的全部者是「root」,爲了下一次在用戶模式下程序能夠正常執行就得改變文件的全部者,使用chown()函數,在上邊的那個demo裏邊就使用了這個函數。