【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