1. 程式人生 > >【Chapter4*程式設計總結一*】(含原始碼)複製空洞檔案且不把0複製到新檔案

【Chapter4*程式設計總結一*】(含原始碼)複製空洞檔案且不把0複製到新檔案

一、寫在前面

不積跬步無以至千里,一點點累積最後達到意想不到的效果。認真對待每一個小細節,一點點改正修訂,往往是問題關鍵所在。

二、coding中遇到的坑

步驟一:建立兩個檔案,一個是空洞檔案,另一個是非空洞檔案,分析比較兩者不同。

2-1 shell中出現亂碼

建立無空洞檔案時,shell中出現亂碼。觀察到新建立的檔案大小為0,沒有資料寫入。初步推測檔案描述符的問題。在這裡插入圖片描述
檢視建立檔案程式碼:

if(fd2=creat(strcat(argv[1],"_copy"),0777)==-1){                     
 	 err_sys("建立無空洞檔案失敗!");     }

OMG!竟然少加了一個括號,也就是把(fd2=creat())作為一個整體,這樣判斷是fd2與-1的關係。OK,就這樣解決了~ 等等,如果對於每個問題,就這麼簡單放過,那就沒有任何總結了呀~一定要搞懂它,這些不起眼的小錯誤是很重要的!

“錯誤”的情況下,原式為,同理是fd2=1==-1,按照C運算子優先順序,==的優先順序高於=,則fd2的值:0,這在linux中對應的是標準輸入,所以在shell框中出現了我們即將寫在fd2中的資料,且fd2檔案大小為0.

fd2=creat(strcat(argv[1],"_copy"),0777)==-1

2-2 有空洞和無空洞檔案佔磁碟塊大小一樣

本來是用磁碟快大小來區分有空洞檔案和無空洞檔案的,這下竟然是一樣的,上圖:c是有空洞,c_copy是無空洞

  4 -rwxrwxr-x 1 fairy fairy    1030 11月  8 15:54 c
  4 -rwxrwxr-x 1 fairy fairy    1030 11月  8 15:54 c_copy

這兩個檔案竟然一致,佔用資料塊大小都是4,看位元組數是1030個位元組,神奇了~按照系統預設的1024位元組塊,應該是1030/1024,剛好超過1個,不足兩個。怎麼變成4個了呢?

原因:在linux的檔案系統中,磁碟的最小物理單元為簇,每次建立一個檔案則為該檔案系統分配一個簇或這簇的倍數(即使檔案大小不足以佔用滿一簇,該簇空餘的磁碟儲存仍舊是該檔案的),系統為檔案分配的簇為4KB。

ls報告塊數單位是1024個位元組,(通過df命令檢視,第一行檔案系統後面1k-blocks)則顯示為4。同理,觀察到所有分配塊數都是4的整數倍。

有的報告塊數單位也是512,這依據於POSIX標準,GNU和POSIX的相容性可檢視部落格:https://www.ibm.com/developerworks/cn/linux/l-cn-posix/index.html

[email protected]:~/Unix_Code/Chapter4$ df
Filesystem     1K-blocks     Used Available Use% Mounted on
udev             1509900        0   1509900   0% /dev
tmpfs             306204     8948    297256   3% /run
/dev/sda1       19478204 13193368   5272356  72% /
tmpfs            1531008      252   1530756   1% /dev/shm
tmpfs               5120        4      5116   1% /run/lock
tmpfs            1531008        0   1531008   0% /sys/fs/cgroup
tmpfs             306204       64    306140   1% /run/user/1000

2-3 segmentation fault (core dumped)

這個問題雖說是老生常談,然而還是一直出錯,遇到一次總結一次。參考部落格:https://www.cnblogs.com/zl-graduate/p/5735288.html

我這次是記憶體上出笑話了,由於申請的陣列是在棧上的,棧的最大空間是8M,使用ulimit命令可檢視,那申請陣列越界就會出現段錯誤。

[email protected]:~/Unix_Code/Chapter4$ ulimit -s
8192
[email protected]:~/Unix_Code/Chapter4$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 11795
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 11795
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

三、總結

3-1 空洞檔案的大小

在建立了一個有空洞和一個無空洞檔案後,使用ls -ls觀察大小。兩個位元組數都是7340038,然而有空洞檔案只佔用了8個1024個位元組,而無空洞檔案佔用了7172個1024個位元組,可以看出佔用磁碟數差距較大。

 8 -rwxrwxr-x 1 fairy fairy 7340038 11月  8 11:12 b
7172 -rwxrwxr-x 1 fairy fairy 7340038 11月  8 11:12 b_copy

計算7172*1024=7344128>7340038,報告顯示的位元組數要大於實際磁碟塊上的位元組數,有可能是檔案系統使用了若干塊存放指向實際資料塊的指標,對磁碟佔用進行了優化。

3-2 複製有空洞檔案思路

對於有空洞檔案複製,cat是把空洞部分直接填充為0,去掉檔案空洞。cp是保留空洞,也建立一個同樣的空洞檔案。這兩個最終生成檔案大小不一致。

重要的,如何判斷該檔案中含有空洞?檔案大小/檔案塊大小>檔案塊數?
可使用stat結構中的3個引數。

st_size 常規檔案長度,單位位元組
st_blksize 最佳IO塊大小
st_blocks 分配磁碟塊數

比如檢視上一步建立的空洞檔案,獲得

[email protected]:~/Unix_Code/Chapter4$ ./4-6 b b4
st_size:7340038
st_blocks:16
st_blksize:4096

複製有空洞檔案,但不把空洞複製到新檔案中,只保留有資料的內容,參考cp的原始碼思路,只是遇到空洞時,跳過即可。參考連結:https://blog.csdn.net/wangxiaoqin00007/article/details/6621209

1、 判斷目標檔案是否存在,如果存在則清空目標檔案,如果不存在則建立目標檔案
2、根據目標檔案的邏輯塊大小,建立拷貝緩衝區
3、判斷原始檔是否有空洞:檔案大小/檔案塊大小 > 塊數 ?
4、讀取原始檔存放到緩衝區,每次讀取一塊
5、在第3步中判斷,如果存在檔案空洞,則對緩衝區資料進行判斷,如果緩衝區中的資料均為0,則認為該資料快為空洞,否則認為是正常檔案資料
6、如果資料塊為空洞,則呼叫lseek,在目標檔案中建立一個空洞;否則拷貝緩衝區資料到目標檔案
7、判斷本次讀取是否讀到原始檔的檔案尾,如果是,則判斷本次讀取的是否是空洞,如果是空洞則在檔案的最後寫入""
8、重複1 ~ 7
9、關閉目標檔案、原始檔

四、原始碼

1)建立兩個檔案,有無空洞:
https://pan.baidu.com/s/1UB8lV3NN2ObIfNVw8d5Tkg
2)複製有空洞檔案,不復制空洞
https://pan.baidu.com/s/1ynMuFDw0syCVjVwGcOVlUg