本文的撰寫主要是在了解,Linux系統呼叫和C語言庫函式的基礎上進行的撰寫代碼,
這篇文章將講解Linux以下的系統呼叫:open()、read()、write()、close()、lseek(),涉及到的c語言庫函式:fopen()、fread()、fwrite()、fclose()、flseek(),
用Linux系統呼叫和C語言庫函式 兩種方式實作檔案拷貝
采用Linux系統呼叫實作檔案拷貝
1.open()
用open函式可以打開或創建一個檔案
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 int open(const char *pathname , int oflag,.../*, mode_t mode * / ) ; 5 6 // 回傳:若成功為檔案描述符,若出錯為- 1open()
pathname 是要打開或創建的檔案的名字,oflag引數可用來說明此函式的多個選擇項,用下列一個或多個常數進行或運算構成oflag引數(這些常數定義在<fcntl.h>頭檔案中):
?O_RDONLY 只讀打開,
?O_WRONLY 只寫打開,
?O_RDWR 讀、寫打開,
在這三個常數中應當只指定一個,下列常數則是可選擇的:
?O_APPEND 每次寫時都加到檔案的尾端,
?O_CREAT 若此檔案不存在則創建它,使用此選擇項時,需同時說明第三個引數mode,用其說明該新檔案的存取許可權位,
?O_EXCL 如果同時指定了O_CREAT,而檔案已經存在,則出錯,這可測驗一個檔案是否存在,如果不存在則創建此檔案成為一個原子操作,
?O_TRUNC 如果此檔案存在,而且為只讀或只寫成功打開,則將其長度截短為0,
?O_NOCTTY 如果pathname指的是終端設備,則不將此設備分配作為此行程的控制終端,
?O_NONBLOCK 如果pathname指的是一個FIFO、一個塊特殊檔案或一個字符特殊檔案,則此選擇項為此檔案的本次打開操作和后續的I/O操作設定非阻塞方式,
?O_SYNC 使每次write都等到物理I/O操作完成,
2.read()
用read函式從打開檔案中讀資料,
#include <unistd.h> ssize_t read(int filedes, void *buff, size_t nbytes) ; //回傳:讀到的位元組數,若已到檔案尾為0,若出錯為-1read()
如read成功,則回傳讀到的位元組數,如已到達檔案的尾端,則回傳0,
有多種情況可使實際讀到的位元組數少于要求讀位元組數:
? 讀普通檔案時,在讀到要求位元組數之前已到達了檔案尾端,例如,若在到達檔案尾端之前還有30個位元組,而要求讀100個位元組,則read回傳30,下一次再呼叫read時,它將回傳0(檔案尾端),
? 當從終端設備讀時,通常一次最多讀一行(第11章將介紹如何改變這一點),
? 當從網路讀時,網路中的緩沖機構可能造成回傳值小于所要求讀的位元組數,
? 某些面向記錄的設備,例如磁帶,一次最多回傳一個記錄,
讀操作從檔案的當前位移量處開始,在成功回傳之前,該位移量增加實際讀得的位元組數,
3.write()
用write函式向打開檔案寫資料
1 #include <unistd.h> 2 ssize_t write(int f i l e d e s, const void * buff, size_t nbytes) ; 3 4 //回傳:若成功為已寫的位元組數,若出錯為- 1write
其回傳值通常與引數nbytes的值不同,否則表示出錯,write出錯的一個常見原因是:磁盤已寫滿,或者超過了對一個給定行程的檔案長度限制,
對于普通檔案,寫操作從檔案的當前位移量處開始,如果在打開該檔案時,指定了O_APPEND選擇項,則在每次寫操作之前,將檔案位移量設定在檔案的當前結尾處,在一次成功寫之后,該檔案位移量增加實際寫的位元組數,
4.close()
可用close函式關閉一個打開檔案:
1 #include <unistd.h> 2 int close (int filedes); 3 4 //回傳:若成功為0,若出錯為-1View Code
5.lseek()
可以呼叫lseek顯式地定位一個打開檔案,
1 #include <sys/types.h> 2 #include <unistd.h> 3 off_t lseek(int filedes, off_t offset, int whence) ; 4 5 //回傳:若成功為新的檔案位移,若出錯為- 1lseek
對引數offset的解釋與引數whence的值有關,
?若whence是SEEK_SET,則將該檔案的位移量設定為距檔案開始處offset個位元組,
?若whence是SEEK_CUR,則將該檔案的位移量設定為其當前值加offset,offset可為正或負,
?若whence是SEEK_END,則將該檔案的位移量設定為檔案長度加offset,offset可為正或負,
經過上面的簡單學習我們可以采用Linux系統呼叫實作檔案拷貝
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<sys/stat.h> 4 #include<fcntl.h> 5 #include<unistd.h> 6 #include<stdlib.h> 7 #include<errno.h> 8 #include <string.h> 9 10 #define BUFF_SIZE 8192 11 12 int main(int argc,char **argv){ 13 14 int from_fd;//源檔案的檔案描述符 15 int to_fd;//目標檔案的檔案描述符 16 off_t file_size=0; 17 char buffer[BUFF_SIZE]; 18 int nread; 19 20 //判斷引數個數是否正確 21 if(argc != 3) 22 { 23 printf("Usage:%s fromfile tofile\n",argv[0]); 24 exit(1); 25 } 26 27 //打開源檔案 28 if((from_fd=open(argv[1],O_RDONLY))==-1) 29 { 30 printf("Open %s Erron\n",argv[1]); 31 exit(1); 32 } 33 34 //創建目標檔案 35 if((to_fd=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR))==-1) 36 { 37 printf("Open %s Erron\n",argv[2]); 38 exit(1); 39 } 40 41 //測得檔案的大小 42 file_size=lseek(from_fd,0L,SEEK_END); 43 lseek(from_fd,0L,SEEK_SET); 44 printf("from file size is =%ld\n",file_size); 45 46 //進行檔案拷貝 47 while((nread=read(from_fd,buffer,BUFF_SIZE)) > 0) 48 { 49 if((write(to_fd,buffer,nread)) !=nread) //將buffer中的資料寫到目的檔案 50 printf("write error"); 51 bzero(buffer,BUFF_SIZE); 52 } 53 close(from_fd); 54 close(to_fd); 55 exit(0); 56 return 0; 57 } 58copy_1
結果可以用diff命令進行檔案的比對

采用C語言庫函式實作檔案拷貝
1.fopen()
fopen庫函式類似于底層的open系統呼叫,它主要用于檔案和終端的輸入輸出,如果你需要對設備進行明確的控制,那最好使用底層系統呼叫,因為這可以避免用庫函式帶來的一些潛在問題,如輸入/輸出緩沖,
1 #include <stdio.h> 2 FILE *fopen(const char *pathname, const char * type) ; 3 4 //回傳:若成功則為檔案指標,若出錯則為 N U L Lfopen
(1)fopen打開路徑名由pathname指示的一個檔案,
(2)type引數指定對該I/O流的讀、寫方式,ANSIC規定type引數可以有15種不同的值
2.fread()、
fread庫函式用于從一個檔案流里讀取資料,資料從檔案流stream讀到由ptr指向的資料緩沖區里,fread和 fwrite都是對資料記錄進行操作,size引數指定每個資料記錄的長度,計數器nitems給出要傳輸的記錄個數,它的回傳值是成功讀到資料緩沖區里的記錄個數(而不是位元組數),當到達檔案尾時,它的回傳值可能會小于nitems,甚至可以是零,
1 #include <stdio.h> 2 size_t fread(void *ptr, size_t size, size_t nitems, FILE * stream) ;fread
3.fwrite()、
fwrite庫函式與fread有相似的介面,它從指定的資料緩沖區里取出資料記錄,并把它們寫到輸出流中,它的回傳值是成功寫入的記錄個數,
1 #include <stdio .h> 2 size_ t fwrite(const void *ptr, size_ t size, size_t nitems, FILE * stream) ;write
4.fclose()、
fclose庫函式關閉指定的檔案流stream,使所有尚未寫出的資料都寫出,因為stdio庫會對資料進行緩沖,所以使用fclose是很重要的,如果程式需要確保資料已經全部寫出,就應該呼叫fclose函式,雖然當程式正常結束時,會自動對所有還打開的檔案流呼叫fclose函式,但這樣做你就沒有機會檢查由fclose報告的錯誤了,
1 #include <stdio.h> 2 int fclose(FILE * stream) ;fclose
5.flseek()、
fseek函式是與lseek系統呼叫對應的檔案流函式,它在檔案流里為下一次讀寫操作指定位置,
offset和whence引數的含義和取值與前面的lseek系統呼叫完全一樣, 但lseek回傳的是一個off_t數值,而fseek回傳的是一一個整數: 0表示成功,-1表示失敗并設定errno指出錯誤,
1 #include <stdio.h> 2 int fseek(FILE *stream, long int offset, int whence) ;flseek
經過上面的簡單學習我們可以采用C語言庫函式實作檔案拷貝
1 #include<stdio.h> 2 #include <string.h> 3 #include<stdlib.h> 4 5 6 #define BUFFER_SIZE 1024 7 8 int main(int argc,char **argv) 9 { 10 11 FILE *from_fd=NULL; 12 FILE *to_fd=NULL; 13 int file_size=0; 14 char buffer[BUFFER_SIZE]; 15 16 //判斷引數個數是否正確 17 if(argc != 3) 18 { 19 printf("Usage:%s fromfile tofile\n",argv[0]); 20 exit(1); 21 } 22 23 //打開源檔案 24 if(from_fd=fopen(argv[1],"r")==NULL) 25 { 26 printf("Open %s Erron\n",argv[1]); 27 exit(1); 28 } 29 30 //創建目標檔案 31 if(to_fd=open(argv[2],"wb+")==NULL) 32 { 33 printf("Open %s Erron\n",argv[2]); 34 exit(1); 35 } 36 37 //測得檔案大小 38 fseek(from_fd,0,SEEK_END); 39 file_size=ftell(from_fd); 40 printf("the from file size is %d\n",file_size); 41 fseek(from_fd,0,SEEK_SET); 42 43 //進行檔案的拷貝 44 while(!feof(from_fd)) 45 { 46 fread(buffer,BUFFER_SIZE,1,from_fd); 47 if(BUFFER_SIZE>=file_size) 48 fwrite(buffer,file_size,1,to_fd); 49 else 50 { 51 fwrite(buffer,BUFFER_SIZE,1,to_fd); 52 file_size=file_size-BUFFER_SIZE; 53 } 54 bzero(buffer,BUFFER_SIZE); 55 } 56 fclose(from_fd); 57 fclose(to_fd); 58 exit(0); 59 return 0; 60 }file_copy
結果可以用diff命令進行檔案的比對

值得注意的是fseek()不像lseek()會回傳讀寫位置, 因此必須使用ftell()來取得目前讀寫的位置,
本文涉及到的關于函式的解釋大部分來自《Linux程式設計》
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/110674.html
標籤:Linux
上一篇:編譯部署MySQL
下一篇:Linux Web服務器集群搭建
