有一段時間我每個星期都要為一個數字反覆折騰:上傳到底能收多大的檔案。看著硬碟裡現成的東西,幾百 KB 的截圖、兩三個 GB 的電影,中間那一檔「剛好 10 MB」「剛好 49 MB」的一個都沒有。我拿電影檔案試過,改副檔名、剪一半,出來的大小從來不是我要的那個整數;寫腳本用 dd 造一個吧,單位又和我以為的不一樣。後來我改成直接按需要的位元組數產生,這件事才從「找檔案」變成「算檔案」。
麻煩的根源:你以為的單位不是它真的單位
我在 任意大小檔案產生 裡可以填位元組、KB、MB、GB,還能精確到個位位元組,檔名和副檔名也自己定。但填之前必須先想清楚一件事:同一個「10 MB」,兩種解釋差了 485760 位元組。
十進位解釋是 1 MB = 1000000 位元組,二進位解釋是 1 MiB = 1048576 位元組,後者比前者多 4.8576%。這個百分比在 MB 這一檔是固定的,往上到 GB 會變成 7.3741824%。我把常用的幾檔算出來擺在這,之後要卡邊界值就直接查這張表。
| 你寫的 | 按 1000 換算(位元組) | 按 1024 換算(位元組) | 差值(位元組) |
|---|---|---|---|
| 1 MB | 1000000 | 1048576 | 48576 |
| 10 MB | 10000000 | 10485760 | 485760 |
| 100 MB | 100000000 | 104857600 | 4857600 |
| 1 GB | 1000000000 | 1073741824 | 73741824 |
所以「限制 10 MB」這句需求,如果對面是按 1024 算的,你給一個正好 10000000 位元組的檔案它是收的;反過來對面按 1000 算、你產生了 10485760 位元組,就會超 485760 位元組被拒。我第一次撞這個坑就是這個方向。要測「卡在上限的那一個位元組」,我現在的寫法是先去確認對面用哪種口徑,再直接填位元組數,不填 MB。
順帶一句老生常談但我真的被問過:標稱 1 TB 的硬碟,在按 1024 折算的系統裡顯示約 931,因為 1000000000000 除以 1073741824 約是 931.32,差的是單位不是缺斤少兩。
全零的檔案壓完只剩幾十 KB,那不是壓縮率高
測壓縮的時候我犯過一次糊塗:產生一個 10 MiB 的檔案,zip 完只剩十幾 KB,我差點把結論寫成「壓縮率一千倍」。錯在我填的是全零。
壓縮壓的是重複和規律,不是體積。全零是規律性最強的內容,DEFLATE 這類演算法對它的理論極限大約是 1032 比 1,也就是說 10485760 位元組的零,理論下限也就一萬位元組上下,實踐中還要看區塊大小和實作。換個填充模式,同樣 10 MiB 可能幾乎壓不動:如果我填的是隨機資料,內容本身沒有可利用的規律,壓完體積基本不變,甚至因為壓縮容器的標頭和校驗資訊反而略微變大。圖片、影片這類已經高度壓縮過的內容,也是同樣道理,你把它再壓一遍掉不了多少。
所以我的規矩是:先決定這次測的是「體積上限」還是「壓縮行為」。測上限用隨機資料,才接近真實檔案的壓縮表現;只有專門要看壓縮演算法對低熵內容的表現時,才用全零。拿全零去報告「我們的上傳體積能壓到幾十 KB」,是把內容特性說成了鏈路能力。要真比較壓縮前後,我會用 圖片壓縮 拿一批正常照片做參照,那張表裡縮小的比例才是可以拿去講的。
檔案「多大」有兩種答案:邏輯大小與實際佔用
另一個讓我誤判過的點:一個檔案的位元組數和它在磁碟上真佔的空間,可以差很多。
只把檔案長度設到位而沒有逐位元組寫過資料的做法,在支援稀疏分配的檔案系統上,邏輯大小可以是 10485760,實際佔用的資料區塊接近零。這時候 ls -l 給你的數字和 du 給你的數字會明顯不一致。我踩過的那次是照計畫灌滿某個測試分割區,用稀疏檔案寫了很久都沒滿,因為真正落到磁碟上的資料少得可憐。
要判斷自己手上是哪一種,我的辦法很笨但可靠:產生以後看實際寫入耗時,或者用 檔案資訊讀取 把大小列出來核對邏輯大小,再配合檔案系統自己的佔用統計比一遍。需要「真的佔住這麼大空間」的容量測試,就不能只看列表裡那個數字。
至於瀏覽器裡產生這種方式的邊界,我是按它的說明用的:串流產生,最大到數百 MB 這個量級;需要幾 GB 的測試檔案,我回到本機命令列去做,不硬撐瀏覽器。
三種填充模式我分別拿來測什麼
| 填充模式 | 內容特點 | 我用來測 | 不適合測 |
|---|---|---|---|
| 隨機資料 | 幾乎不可壓縮,體積接近真實檔案 | 上傳下載限速、體積上限、磁碟佔用 | 壓縮演算法的極限表現 |
| 全零位元組 | 規律性最強,壓完極小 | 只看介面是否按位元組數放行 | 壓縮比、真實頻寬 |
| 自訂文字循環 | 可預測的可讀內容 | 解析、匯入、預覽邏輯 | 高熵內容的傳輸表現 |
測限速這件事我也想補一句:拿一個 100 MiB 的檔案傳完用了 25 秒,是 104857600 除以 25,等於 4194304 位元組每秒,換成兆位元要乘 8 再除一百萬,約 33.6 Mbps。位元組和位元這兩個 B 我當年混淆過一次,結果把鏈路速度估小了八倍。
常見問題
Q:我要「剛好 10 MB」,到底該填什麼數?
先問對面按 1000 還是按 1024。按 1000 就填 10000000 位元組,按 1024 就填 10485760 位元組。這兩個數差 485760 位元組,隨便挑一個都可能不是你要的。測試上限時我一般從小的那一檔起步,再一檔一檔往上加。
Q:為什麼產生的檔案壓完只有幾十 KB?
因為你填的是零或者循環重複的文字,壓縮掉的是規律不是體積。想讓它壓不動,就換隨機資料填充。
Q:測上傳限制,只測一個剛好達標的檔案夠嗎?
不夠。我至少打三個點:剛好在限內、正好等於限制值、超一個位元組。中間那一點最容易被「小於等於」和「小於」的寫法搞錯,光測一個正常大小的檔案試不出來。
Q:邏輯大小對上了,為什麼磁碟沒漲?
可能是稀疏分配,長度寫到位而資料沒落盤。用檔案系統的佔用統計再核一遍,別只看列表裡的位元組數。
回到最初那個「找一個剛好 10 MB 的檔案」的問題。我現在的做法是先確認對面用 1000 還是 1024,然後按位元組數產生,填充選隨機資料,產生完核對一次大小再傳。聽起來只是多算了一步,但它把我從前反覆試錯的那半小時徹底省掉了。