在日常工作中,為了驗證某些場景下的功能,常常需要人為構造一些龐大的文件進行測試。有時,我們需要用這些大文件來測試下載速度的表現(xiàn),而有時則是為了填充磁盤空間以測試系統(tǒng)的反應。偶爾,我們會偶然瀏覽到一些網(wǎng)絡博文,其中介紹了如何構造大文件的方法。然而,當真正需要這些信息時,卻發(fā)現(xiàn)已經(jīng)無法找到那些文章了。因此,我決定總結一下在linux系統(tǒng)下生成和處理大文件的方法。
盡管在Linux系統(tǒng)中有一些命令,比如vi和touch,可以用來創(chuàng)建文件,但是如果需要生成一個大小為10GB甚至100GB的大文件,這些命令就顯得力不從心了。這時就需要一些能夠快速生成大文件的命令。下面將介紹幾個這樣的命令,并探討它們的使用方法和區(qū)別。
一、生成大文件命令
1、dd
dd (device driver) 命令表示用指定大小的塊拷貝一個文件,并在拷貝的同時進行指定的轉換。
語法如下:
從 source 讀取并拷貝內容到 destination, source 和 destination 都是文件,前者是讀取的文件,后者是寫入的文件。
?
- bs: 表示塊的大小,單位是字節(jié),后綴中帶了字母B的換算單位都是1000, 比如:1KB = 1000 Bytes、1MB = 1000 * 1000 Bytes、1GB = 1000 * 1000 * 1000 Bytes, 后綴省略了字母 B的換算單位是 1024, 比如:1K = 1024 Bytes、 1M = 1024 * 1024 Bytes、1G = 1024 * 1024 * 1024 Bytes
- count: 表示塊的數(shù)量,表示 dd 命令需要執(zhí)行多少次讀取及寫入的操作 bs 乘以 count 就表示目標文件的大小,也即需要創(chuàng)建的文件的大小
比如:下面的命令可以創(chuàng)建一個 10G 大小的文件
[root@localhost?tmp]#?dd?if=/dev/zero?of=testfile?bs=1G?count=10 10+0?records?in 10+0?records?out 10737418240?bytes?(11?GB,?10?GiB)?copied,?5.11256?s,?2.1?GB/s [root@localhost?tmp]#?du?-h?testfile 10G?????testfile
上面的命令表示從 /dev/zero文件每次讀取 1G大小的數(shù)據(jù)并寫入當前目錄中的 testfile 文件, bs=1G表示塊大小是1G, count=10表示共有10個塊, 所以目標文件最終的大小是: 1G * 10 = 10G。
/dev/zero 是一個特殊的字符設備文件,當讀取它的時候,它會返回空數(shù)據(jù),俗稱為0源,所以這里if=/dev/zero表示從 /dev/zero讀取空的數(shù)據(jù)寫入 testfile 中。
使用命令 du -h testfile 可以看出 testfile 大小是的確是 10G。
從上述結果可以得知,用 dd 命令創(chuàng)建一個 10G 大小的文件僅僅花費了約 5.1 秒,速度是比較快的。
?
擴展:/dev/urandom、/dev/random、/dev/zero、/dev/null解析:
- /dev/urandom和/dev/random都可以產(chǎn)生隨機的ASCII碼字符流,其中/dev/random依賴系統(tǒng)中斷,當系統(tǒng)中斷不足時,/dev/random設備會“掛起”。/dev/urandom不依賴系統(tǒng)中斷,所以在生成特定大小文件時一般使用/dev/urandom,不使用/dev/urandom。
- /dev/zero “零”設備可以無限的提供空字符,產(chǎn)生二進制的零流
- /dev/null “空”設備,像”黑洞“一樣,所有寫入它的內容都會永遠丟失,也不會讀取到任何內容。常用于禁止標準輸出和標準錯誤的輸出,比如抓包命令:tcpdump -i eth1 -w /tmp/packet.pcap >/dev/NULL &
2、yes
dd 命令創(chuàng)建的是空字符的文件,如果想創(chuàng)建包含自定義的字符的文件,則可通過 yes 命令,它的作用是循環(huán)輸出一行指定的字符串,直到進程結束;為了控制文件的大小并打破循環(huán),我們借助 head 命令來實現(xiàn)。
使用 yes 命令創(chuàng)建包含指定內容文件的語法如下:
yes?[String]?|?head?-c?[size?of?file]?>?[name?of?file]
?
如下示例是向文件 yesfile 寫入,每行的內容是: this is my test file , 一直到文件大小達到 10G。
[root@localhost?73]#?yes?"This?is?my?test?file"?|?head?-c?10G?>?yesfile [root@localhost?73]#?du?-h?yesfile 10G?????yesfile [root@localhost?73]#?time?yes?"This?is?my?test?file"?|?head?-c?10G?>?yesfile real????0m6.635s user????0m0.882s sys?????0m9.645s
為了查看使用yes創(chuàng)建大文件的速度,我們這里通過time命令量測yes指令執(zhí)行時所需消耗的時間及系統(tǒng)資源,從結果可以看出,yes命令創(chuàng)建一個10G 的文件花費了 9.6 秒,比dd命令慢一些。
3、fallocate
fallocate 命令表示為文件預先分配或取消分配空間。
語法如下:
fallocate?-l?[size?of?file]?[name?of?file]?
?
- -l 選項表示文件大小,單位是字節(jié),后面可以接 K、KB、M、MB、G、GB等單位
如下示例是使用fallocate命令是創(chuàng)建一個 10G 大小的文件
[root@localhost?73]#?time?fallocate?-l?10G?falfile real????0m0.027s user????0m0.000s sys?????0m0.001s [root@localhost?73]#?du?-h?falfile 10G?????falfile
這里通過time命令量測fallocate指令執(zhí)行時所需消耗的時間及系統(tǒng)資源,從結果可以看出:fallocate命令創(chuàng)建一個 10G 大小的文件竟然只花費了 0.001 秒,速度可謂是極快的。
4、truncate
truncate 命令表示將文件的大小縮小或擴展到指定的大小。
語法如下:
truncate?-s?[file-size]?[name?of?the?file]
?
- -s 選項表示文件大小,單位是字節(jié),跟 fallocate 命令一樣,后面可以接 K、KB、M、MB、G、GB等單位
如下示例為使用 truncate 命令創(chuàng)建一個 10G 大小的文件。
[root@localhost?73]#?time?truncate?-s?10G?trunfile real????0m0.025s user????0m0.000s sys?????0m0.001s #查看文件實際占用磁盤空間大小 [root@localhost?73]#?du?-h?trunfile 0???????trunfile #查看文件顯示大小(邏輯大小) [root@localhost?73]#?ll?-h?trunfile -rw-r--r--?1?root?root?10G?Jul??3?04:41?trunfile
這里通過time命令量測fallocate指令執(zhí)行時所需消耗的時間及系統(tǒng)資源,從結果可以看出,truncate命令創(chuàng)建一個10G的文件也只花費了 0.001 秒,和 fallocate 基本一樣。但是, du -h trunfile 命令的結果顯示 trunfile 大小為 0。
原因是 truncate 命令 創(chuàng)建的是一個稀疏文件(空洞文件)而不是實際的文件 ,稀疏文件不會占用實際的磁盤空間,文件只是看上去邏輯大小比較大,但實際占用空間卻是0。
?
提示:
- ls顯示文件的“邏輯上”的size, 這不是文件真正占用磁盤空間大小,這部分空間也會被其他進程使用
- du顯示文件“物理上”的size,即du顯示的size是文件在硬盤上占據(jù)了多少個block計算出來的
注意:fallocate 命令只支持 btrfs、ext4、 ocfs2、xfs 這幾種文件系統(tǒng),而 truncate 命令支持所有的現(xiàn)代文件系統(tǒng)。
二、優(yōu)劣分析
對比上述不同命令創(chuàng)建 10G的文件的差異,尤其是生成速度方面,比較如下:
?
- dd 5.1秒
- yes 9.6秒
- fallocate 0.001秒
- truncate 0.001秒
根據(jù)上述結果可知,不同命令創(chuàng)建文件的速度方面相差了幾千倍,為什么會有如此大的差距呢?我想可能在于以下區(qū)別:
?
- dd 需要進行寫文件操作,進行大量的IO
- yes 需要進行寫文件操作,進行大量的IO
- fallocate 將空間分配給文件,但不會寫入任何數(shù)據(jù)到文件中
- truncate 創(chuàng)建的是稀疏文件,不會寫入任何數(shù)據(jù)到文件中
dd和yes都有寫文件操作,而這需要大量的 IO 時間,所以同樣創(chuàng)建10G的文件,它們比fallocate和truncate要慢很多。如果對生成文件的速度沒有很高的要求且對內容無要求的情況下首選dd,如果希望自定義文件內容的話,則使用yes。如果想快速地生成超大文件,比如 1 秒內創(chuàng)建一個 100G 的文件,選擇fallocate和truncate ,如果還需要確保文件是實際占用磁盤空間的話,則只能選擇fallocate 。
大部分情況下,fallocate都能滿足要求,因此,Linux中生成大文件時,建議使用fallocate命令。
三、大文件處理
在Linux下vim、cat打開超大文件,受到內存硬件原因,往往會遇到打不開或者內存使用過高導致卡機問題。針對Linux大文件處理一般通過Linux提供的命令split切割成小文件再進行處理。
1、文件分割
針對大文件處理,Linux系統(tǒng)提供了split 工具將大文件切分為多個小文件,以方便通過vi,cat等命令進一步處理。既然要生成多個小文件,必然要指定切分文件的單位,支持按行切分以及按文件大小切分,另外還需解決小文件命名的問題。例如,文件名前綴、后綴。如果未明確指定前綴,則默認的前綴為”x”。
語法如下:
split?[選項]...?[待分割的文件?[小文件的前綴]]
選項含義如下:
- -a: 指定輸出文件名的后綴長度(默認為2個:aa,ab…)
- -b:指定每一輸出文件的大小,單位為 byte
- -C:每一輸出文檔中,單行的最大 byte 數(shù)
- -d:使用數(shù)字作為后綴
- -l:行數(shù)分割模式(指定每多少行切成一個小文件;默認行數(shù)是1000行)
示例如下:
#行切割文件且使用數(shù)字后綴 [root@localhost?test]#?split?-l?50000000?-d?-a?3?yesfile?yesfile_ [root@localhost?test]#?ls?-l total?20971536 -rw-r--r--?1?root?root?10737418240?Jun?30?09:28?yesfile -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_000 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_001 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_002 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_003 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_004 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_005 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_006 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_007 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_008 -rw-r--r--?1?root?root??1050000000?Jun?30?09:39?yesfile_009 -rw-r--r--?1?root?root???237418240?Jun?30?09:39?yesfile_010 [root@localhost?test]# [root@localhost?test]#?du?-h?yesfile_000 1002M???yesfile_000 [root@localhost?test]#?tail?-5?yesfile_000 this?is?my?test?file this?is?my?test?file this?is?my?test?file this?is?my?test?file this?is?my?test?file #按字節(jié)大小分割 [root@localhost?test]#?split?-d?-b?1G?yesfile?yes_ [root@localhost?test]#?ls yes_00??yes_01??yes_02??yes_03??yes_04??yes_05??yes_06??yes_07??yes_08??yes_09??yesfile [root@localhost?test]#?du?-h?yes_00 1.0G????yes_00 #指定輸出文件后綴長度 [root@localhost?test]#?split?-d?-b?1G?yesfile?-a?3?yes_ [root@localhost?test]#?ls yes_000??yes_001??yes_002??yes_003??yes_004??yes_005??yes_006??yes_007??yes_008??yes_009??yesfile
2、文件合并
在 Linux 系統(tǒng)下使用 cat 命令進行多個小文件的合并也很方便。cat命令用于連接文件并打印到標準輸出設備上。
語法如下:
cat?[-AbeEnstTuv]?[--help]?[--version]?fileName
參數(shù)說明:
- -n 或 –number:由 1 開始對所有輸出的行數(shù)編號。
- -b 或 –number-nonblank:和 -n 相似,只不過對于空白行不編號。
- -s 或 –squeeze-blank:當遇到有連續(xù)兩行以上的空白行,就代換為一行的空白行。
- -v 或 –show-nonprinting:使用 ^ 和 M- 符號,除了 LFD 和 TAB 之外。
- -E 或 –show-ends : 在每行結束處顯示 $。
- -T 或 –show-tabs: 將 TAB 字符顯示為 ^I。
- -A, –show-all:等價于 -vET。
- -e:等價于”-vE”選項;
- -t:等價于”-vT”選項;
示例如下:
#把testfile的文檔內容加上行號后輸入yesfile這個文檔里 [root@localhost?tmp]#?cat?-n?testfile?>?yesfile #使用tail讀取yesfile文件的末尾幾行,第一列為行號 [root@localhost?tmp]#?tail?yesfile 4993211?this?is?my?test?file 4993212?this?is?my?test?file 4993213?this?is?my?test?file 4993214?this?is?my?test?file 4993215?this?is?my?test?file 4993216?this?is?my?test?file 4993217?this?is?my?test?file 4993218?this?is?my?test?file 4993219?this?is?my?test?file #將test目錄下之前分割的小文件通過cat命令進行合并,重新生成yesfile文件 [root@localhost?test]#?cat?yes_*?>?yesfile #生成后的yesfile文件大小依然是10G [root@localhost?test]#?du?-h?yesfile 10G?????yesfile
四、總結
通過本文的介紹,我們了解了如何在Linux系統(tǒng)下進行大文件生成以及分割,并掌握了一些常見的技巧和注意事項。無論是處理大文件還是日志記錄,都可以采用上述方法來提高效率。