標籤:des style blog http io ar color os sp
原文:複製一個空洞檔案且忽略掉其空洞內容
首先說一下什麼叫做空洞檔案!比如說,下面這段代碼:
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<errno.h> 5 #include<sys/types.h> 6 #include<sys/stat.h> 7 #include<fcntl.h> 8 #include<unistd.h> 9 10 #define MODE O_CREAT|O_RDWR|O_TRUNC11 int main(int argc,char *argv[])12 {13 int fd;14 15 if(argc != 2)16 {17 printf("Usage:%s <filename>\n",argv[0]);18 exit(EXIT_FAILURE);19 }20 if(-1 == (fd=open(argv[1],MODE,0644)))21 {22 printf("%s[open]%s\n",argv[0],strerror(errno));23 exit(EXIT_FAILURE);24 }25 if(-1 == write(fd,"abcde",5))26 {27 printf("%s[write]%s\n",argv[0],strerror(errno));28 exit(EXIT_FAILURE);29 }30 if(-1 == lseek(fd,5,SEEK_END))31 {32 printf("%s[lseek]%s\n",argv[0],strerror(errno));33 exit(EXIT_FAILURE);34 }35 if(-1 == write(fd,"ABCDE",5))36 {37 printf("%s[write]%s\n",argv[0],strerror(errno));38 exit(EXIT_FAILURE);39 }40 if(-1 == close(fd))41 {42 printf("%s[close]%s\n",argv[0],strerror(errno));43 exit(EXIT_FAILURE);44 }45 printf("空洞檔案已經建立成功!\n");46 return 0;47 }
在這段代碼中,我首先在檔案中寫入abcde五個位元組的內容,然後在把檔案指標從檔案尾端向後移動5個位元組,再寫入ABCDE5個位元組的內容!這樣在這個檔案中,兩次abcde中間就會產生一個5個位元組空洞,這個空洞的內容都被寫成了0。檔案的空洞並不要求在磁碟上佔用儲存區,具體的處理方式和檔案系統的實現有關!我這個檔案如果用vim開啟的話會是這樣的效果!
中間藍色的^@就表示內容為0的空洞!
接下來,我們再來談一談如何來複製一個空洞檔案,並且讓忽略掉它的空洞部分的內容!這裡我們就利用了空洞內容為0的這個特性!具體的實現方法就是通過查看讀出來的檔案內容的值是否為0,如果是則忽略,否則就儲存起來!具體的實現代碼如下:
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<errno.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#define MODE O_RDWR#define SIZE 4096int main(int argc,char *argv[]){ if(argc != 3) { printf("Usage: %s source_file destination_file\n",argv[0]); exit(EXIT_FAILURE); } int fd_s,fd_d; //分別用來儲存讀出和寫入的檔案內容 char buf_r[SIZE],buf_w[SIZE]; //寫入緩衝指標的計數器 int w_l; //read_length,write_length //讀出和寫入的長度 int r_len,w_len; if(-1 == (fd_s=open(argv[1],MODE))) { printf("%s[open]%s\n",argv[1],strerror(errno)); exit(EXIT_FAILURE); } if(-1 == (fd_d=open(argv[2],MODE|O_CREAT|O_TRUNC,0644))) //如果目標檔案已經存在,則將其截短成0 { printf("%s[open]%s\n",argv[2],strerror(errno)); exit(EXIT_FAILURE); } //如果檔案的內容過於龐大,我這裡是分批儲存的!且在《Unix環境進階編程》的3.9節已經論證過當SIZE為4096的時候I/O的效率最佳! while((r_len=read(fd_s,buf_r,SIZE)) > 0) { w_l=0; //將讀出內容中的非空洞內容賦值到buf_w中 for(int i=0;i<r_len;i++) { if(buf_r[i] != 0) buf_w[w_l++]=buf_r[i]; } //這裡得到的w_l表示的是字元數組的長度,注意數組是從0開始的 if(-1 == (w_len=write(fd_d,buf_w,w_l))) { printf("%s[write]%s\n",argv[0]+2,strerror(errno)); exit(EXIT_FAILURE); } } if(-1 == close(fd_s)) { printf("%s[close]%s\n",argv[1]+2,strerror(errno)); exit(EXIT_FAILURE); } if(-1 == close(fd_d)) { printf("%s[close]%s\n",argv[2]+2,strerror(errno)); exit(EXIT_FAILURE); } return 0;}
上面那個程式的思路就是每次讀取4096位元組,分批讀取源檔案的內容到buf_r中,然後檢查buf_r的內容,如果是0則忽略,否則就暫存到buf_w中,然後將其寫入到目標檔案中!
檢驗這個程式的運行結果我用了一個較大的空洞檔案,具體的運行結果如:
複製一個空洞檔案且忽略掉其空洞內容