為什麼打開一個幾兆的 .jpg 圖片比打開一個幾兆的 .txt 文本文檔快很多?
我從編程的角度去考慮。這兩種內容有一些區別:
- 圖像的內部表示尺寸是已知、確定的,例如 512?512;純文本具有多少行,每行多少字,是在解析後才能得知。因此,圖像的內存分配較為簡單。
- 圖像在讀取後,不常會插入像素,而且更多時候「打開」是指「檢視」,不需要考慮編輯;文本更多時候提供編輯功能,在數據結構上要考慮插入字元、行等操作,不能簡單地用一段內存來存儲所有內容。當然,也有一些純檢視文本的工具,例如網頁瀏覽器。
- 一些圖像處理可使用 SIMD 甚至 GPU 協助,文本可用到的機會較少。
- 文本的渲染複雜,但一般只需要渲染整個文件的一個區域。
由於圖像的內容表示及解析方法比較直觀通用,通常可使用經過高度優化的庫。而文本則要視需求設計數據結構、解析及渲染,組合較多,對某些情況(例如大文件)可能優化不足。
按照Windows的標準處理一個純文本文件有令人難以想像的複雜度,尤其是打開了自動換行的情況下:
- 識別編碼並轉化為Unicode
- 按換行符將文本拆分成行,每行當作一個段落處理
- 按照Unicode語義分析文本,將文本按照不同語言分拆成從左到右和從右到左的段。這一步是比較複雜的,某些語言在字元串當中是abcdefg的順序,但顯示的時候必須從右到左顯示為gfedcba,但是如果再中間換了行,比如在d的後面換行,又要變成dcba
gfe……而且,按照規範,從左到右的文本中可以嵌入從右到左的文本,從右到左的文本又能嵌入從左到右的文本,這個嵌入還是可以嵌套的,比如最外層是從左到右,裡面有一段文字是從右到左,這個從右到左的文字裡面又嵌入了從左到右的詞…… - 將每個從左到右或者從右到左的段進一步進行語義分析,找出:字元邊界(部分連續的多個Unicode字元是不可拆分的,比如字元與上面的注音符號,選擇文本的時候只能選到字元邊界,不能選進字元里);可以換行的斷點;可以分詞的斷點(在編輯器中雙擊一個字元會選中詞,對英文就是按空格,對中文一般就是選中單字);定寬的空格;不定寬的空格等等。這個過程對不同的語言有完全不同的處理方式,需要按照字元選擇相應語言的處理方法。
- 嘗試將文本轉換為符號(Glyphs)。Unicode字元到符號的映射並不是一一對應的,對於某些語言來說,字元的上下文會影響字元的顯示,讓字元顯示為完全不同的樣子;符號的排布並不是簡單的從左到右按順序,某些字元需要在之前字元的基礎上調整位置(比如上下標,注音符號,還有泰語裡面那個會飛出去的字元)從右到左的文本也會有影響,在處理時會將符號逆序,統一處理成從左往右。
這一步對於自動換行的程序來說要更複雜一些,不過事實上所有的文本編輯器都自動換行,區別只是打開自動換行的時候換行按照當前視口的寬度,而關閉的時候按照一個固定的最大寬度(你可以嘗試在記事本裡面輸入非常多的字元,你會發現最終還是換行了的)。對於自動換行的程序來說,不能一次性轉換成符號然後判斷寬度,因為不同的輸入內容可能導致不同的符號輸出,而且混排從右到左和從左到右的情況下,換行會導致符號順序發生嚴重的變化,因此唯一可靠的方法是按照前一步找出的所有可以換行的斷點分別嘗試,直到得到的符號總寬度超過行寬為止。在前一個斷點將文本拆開換行。如果第一個可以換行的斷點就超出寬度了,還需要再嘗試從詞或者字的邊界換行。 - 處理對齊。文本顯示有左對齊、右對齊、中間對齊、兩端對齊四種主流的方式,如果最外層文本從右到左顯示一般基礎是右對齊,否則是左對齊,內部嵌入的文本不影響對齊方式。前三種相對處理起來容易,兩端對齊就要用到前面計算出的定寬空格和不定寬空格的問題了:在某些語言中,某些空格必須是固定的寬度,不能變得更寬,而某些空格允許在兩端對齊的時候增加寬度,在兩端對齊的時候,必須只加寬那些可以變寬的空格,而不加寬那些不能變寬的空格。
- 渲染文字。按照符號和字體,將字體里的圖畫出來,變成圖像。字體可能按不同字型大小有不同的繪製方法,還有抗鋸齒、ClearType等處理,不再細說。
- 計算行高。相對簡單,一般按照字體、字型大小折算一下就行了。
即便如此,我們還是有必要指出:對於現代的文本編輯器,即使是Windows 10的記事本,也能瞬間打開一個幾兆的文本文件,這主要還是演算法優化的效果,以前舊版本總是會嘗試一次把所有的文本都渲染出來,自然就比較慢。而且以前的GDI介面也比較慢。
因為你用的文本編輯器試圖把幾兆的文本從頭渲染到尾然後再顯示。而這意味著幾千上萬屏幕的輸出。而幾兆圖片輸出一個屏幕就搞定了,最多四個屏幕不能再多。
當然優化好些的文本編輯器是可以秒開的。例如一些圖書閱讀器本來就為此進行了優化。隨便舉個例子,多看閱讀打開幾兆的文本是秒開,因為只渲染當前頁面。這件事情上,本質複雜度和偶然複雜度都有份。
偶然複雜度是 Text editor 優化不好。
本質複雜度是文本編輯比圖片編輯要複雜的多。文本編輯要處理插入,游標的上下左右移動。初始的 layout 和每個字元的 render 也要時間。所以內部要建立遠比一維 char 數組複雜的數據結構。渲染出來的 bitmap 也要比普通的照片大。可能還沒法一次放到顯卡里。View 還要處理 scrolling 和 on-demand rendering。
而圖片就用二維數組就行了。JPEG decode 之後直接給顯卡就行了。一般大小的圖片顯卡直接就處理了。
和你想像的相反,排版是非常困難的事情。你去看下 http://Unicode.org 底下那幾個定向、斷行等演算法就知道了——排版是無比複雜的。@Mili 他們組裡面一票數學家,乾的就是一個事:寫 WORD 的主排版引擎。
另外說 Notepad2 等快的,我告訴你們,能正確處理組合文字、CJK 禁則和 RTL 的編程用文本編輯器一個都沒有。對,一個都沒有。
這取決於你用什麼app。比如你用Win10內置的Photos試試,300k的jpg都能讓你十多秒之後才看到個模糊的圖像!並且要關掉重開,才能看到清晰的!
磁碟讀取基本是一樣的,差別主要在解析-顯示環節。
文本的顯示相對複雜。以漢字為例,兩個位元組的漢字,需要查錶轉換成至少48X48的點陣字元,現代true type字元消耗資源經常更大。此外,更高DPI的顯示設備往往也需要更多的像素點去顯示一個字元。
換句話說,兩個位元組的漢字,需要先通過一個查表運算轉換成至少36個位元組的圖形化數據,然後再實時渲染到屏幕上。這就造成數據量激增。
相對來說,圖片顯示就要簡單的多。
另一個方向,很少有類似「用一個單獨的文本文件存一整本小說」的需求。翻頁、定位都太痛苦了。大部分文檔,字元數目都在數萬以下,每個章節存一份文本文檔就行了,存一起沒法看。
所以,很少有文本編輯器會針對「打開一個數百萬字的文件」做優化——當然,碼農們用的專業文本編輯器除外——比如windows的記事本,就是把上百萬字一下子全部渲染出來,相當於一下子顯示了個幾千屏大的超級大圖,你說能不慢嗎。
如果每次只處理並顯示一屏(玩過編程的都知道fseek的妙用),文本顯示甚至圖文混排顯示也可以很快。
而動輒幾兆甚至幾十上百兆的圖片則比比皆是。為了優化這類圖片的顯示,甚至有專門的規範,使得輪廓信息放在前面、細節信息在後面。於是圖片顯示可以邊解析邊顯示,只是有一個先模糊後清晰的過程,這就使得圖片載入給人的感覺是非常快。
因為你沒用程序員們用的文本編輯器……
同樣是一個fdde四個字母,圖片中#fdde僅僅是一個像素點,而txt中fdde四個字母可能要經過truetype字型檔解析為幾十段矢量貝塞爾曲線,然後還要根據屏幕解析度等進行scale,佔用內存和cpu高太多了。
另外,如果你只渲染txt的第一頁或前幾頁的話,那肯定比渲染整張jpg快的多。撿起1斤芝麻快還是2斤西瓜快???
你可以反過來想想:
當你在觀看一張若干兆的照片(點陣圖),你能讀到多少有效信息?
當你讀一份500萬字的txt格式(1K=512字)小說,你能讀到多少信息?
從信息熵上,兩者就差了不止一個等級!
當然,這麼說,確實有點玄乎,畢竟我們假定,在電腦硬碟里,兩者所佔的磁碟空間大小是一致的。
我們也可以從其他角度去解答。Windows的記事本工具,默認打開txt的方式,是全部渲染,一份包含數百萬文字的txt文檔,滑鼠滾輪要滾好久才能拉到底。
呈現txt文檔至「邏輯上」的全屏幕(實際屏幕沒那麼長),需要CPU來負責理論上每一行占屏幕的圖像渲染工作,CPU是一種通用計算核心,沒有單獨的為圖形顯示做優化,讓CPU做成千上萬行(1920x1080解析度,系統顯示字體默認,每行大概有100個字)字的圖形渲染工作,每行倒是簡單,但要在短時間內重複渲染出這麼多行,也是辛苦CPU了。
這種任務,交給擅長並行計算的GPU更合適
決定jpg圖像的關鍵信息,主要在SOF0標記段里,通常一個顏色分量(簡單的可以理解成一個色塊)為9位元組,比txt的基本單位(1位元組)大了九倍。
所以從理論上來說,完全打開相同大小的jpg和txt文件,前者的理論速度要比後者要快
另一個值得注意的地方是,前面提到過,Windows記事本默認是渲染所有txt文字的,而一般的點陣圖查看器,打開一張圖片至適應當前屏幕的大小,讓觀看者看得「差不多」就行了。
不停的放大某個點陣圖的位置,你就會發現成規律的,模糊的色素塊,但這樣不適合人眼的全局預覽,把每個局部都看清楚後,我們的大腦也記不清這張圖片到底是個什麼鬼
其實,聰明的你已經發現了,jpg之所以打開「更快」,是因為計算機「覺得(其實是開發點陣圖查看器的人啦)」,不論多大的圖片,儘可能的放在當前這個屏幕里,供人眼查看就夠了。順便還可以犧牲掉諸多不必要的色塊與細節的處理。
為了節省容量,大部分 jpg格式的圖片,還會默認放棄掉許多高解析度數據塊做編碼,放棄了許多「不討人眼睛好」的信息,在渲染的過程中,CPU也可以按需、按層級渲染,節省了CPU的工作壓力。
上面有不少答主說了,如果你使用一款默認只渲染當前打開頁的txt文本閱讀器,打開txt文檔的速度,就一定快多了。
說了這麼多,讓你做以下第一個思考,想一想,如果我們不用「討巧」的方式,打開一張點陣圖呢?
用 PS等圖片處理軟體,打開一張若干兆的點陣圖,然後不停的放大某一局部,看看電腦是不是變慢了(i7+固態硬碟+32GB內存的大佬請無視);
第二個思考:許多細碎的小區塊,單一列隊渲染VS完整的區塊,按需渲染
將一部 1個小時的視頻,按每個幀,截成108,000張單獨的圖片,並且用 0.03s的間隔,將這些圖片,播放幻燈片,看看相比直接播放視頻,誰更流暢?
渲染600*800的文字比600*800的像素慢多了,更何況幾兆的txt,,保守估計是上萬乘以800.
我的體驗至少是win的記事本程序打開文件時就要做完全部內容的渲染,,不信的話可以用你這幾兆的txt,選擇「自動換行」或者拉動窗口大小來觸發一下重新渲染,你看下是否消耗和打開差不多相同的時間?
提問前提不成立,你用 photoshop 打開 jpg,和用 less 打開 txt 比較下,就知道了。
「打開」所用的工具不同,速度就不同,因為作用不同。只是恰好你用來比較的兩個工具,一個快一個慢而已,不是說兩種格式一定就那樣。
實際上以現在的硬碟讀寫速度,打開一個 100MB 的文件都是一眨眼的功夫,所以瓶頸根本不在 I/O 上,讀取一張圖片,除了 I/O 操作以外還涉及解碼的步驟,最後則是 blit 到顯示設備上,需要操作的顯存大小也許只有顯示窗口的大小,就算是軟體渲染,像素拷貝的時間都是很短的。事實上你打開一個幾十 MB 的圖片,如果 Surface 很小,總共消耗的時間算上 I/O、解碼、插值計算也不會太長。
但是打開 txt(我姑且認為題主用的記事本)從文件讀取完畢到首屏渲染完畢需要經歷一個相當耗時的步驟,那就是文字的排版計算,記事本個人猜測沒有使用行 buffer,而是一個 Windows 標準的 Edit 控制項,即便是不用渲染全部 glyph 也是要計算 ScrollBar 高度的,實際上打開大文本所消耗的時間都在這上面。而很多現代的編輯器都採用了行 buffer,按行讀取以後先排版首屏能顯示的行,根據行的平均高度估算整體高度來渲染 ScrollBar,這樣,隨著用戶捲動 viewport,編輯器再即時進行排版渲染,效率就高很多。
用一個最簡單的思維。
- 什麼是打開?就是把內容顯示在屏幕上;
- 怎麼顯示到屏幕上?假設窗口大小是M*N像素,那麼顯示到屏幕上就是計算出屏幕上M*N個像素點的RGB值。
- 什麼是圖片?假設圖片大小是M*N像素,那麼一張圖片就是M*N個像素點的RGB值。一張bmp圖片就是把這些像素點的值完整地存下來的。jpg有點不一樣,還進行了壓縮編碼。
可以說,問題語境下的「打開一個文件」等價於「生成一張bmp圖片」。
這裡要說明,打開圖片並不一定總是比打開文本快,所以以下也並不是一個嚴格的證明。
下面兩個哪個快?
- 給定一張jpg圖片,經過計算,生成一張bmp圖片A.bmp
- 給定一個文本文檔,經過計算,生成一張bmp圖片B.bmp
結果已經可以猜到了,由圖片生成圖片更快。
還可以比較A.bmp和B.bmp的大小。可以做實驗
- 把一張1M大的jpg圖片轉成bmp圖片
- 把一個1M大的文本文檔打開,把所有內容截圖,保存為bmp圖片
顯然,A.bmp更小。
用我這個門外漢的角度來說:
打開一個幾兆的JPG,你可以直接看到圖片的內容。
打開一個幾兆的TXT,你猜猜滾動條你要拉多久,拉的階段要刷新多少次畫面。
一箱棉花為什麼比一箱鐵輕很多?
順便解釋一下,免得有人人看不懂
不同文件的尺寸相當於不同物質的體積
物質的密度不同導致質量不同,不同文件格式的解析、表現複雜度當然也是不同的
舉個簡單的誰都能理解的例子,假設把一個文件連續壓縮 100 次,那麼你要查看原始文件就要連續解壓 100 次
如果你覺得 100 次還是很快,那就 1000000000000000 次,這時候你終於就知道,同樣的尺寸,解析起來還是。。。。。。挺費勁的
這說明了解析時間和文件尺寸無關
看你用什麼工具打開txt了,比如你用windows自帶的那個notepad(尤其是xp版的),你可能需要好幾秒,甚至1分鐘以上,如果你用notepad++ 或是sublimetext 之類的工具打開幾mb的文件也就是秒秒鐘的事
從圖像的渲染來說,打開一個圖片,一個位元組可能隻影響一個像素左右的點,而一個位元組的文本,可能需要幾十上百個像素來渲染,所以渲染同樣大小的文本工作量比渲染圖片要大的多
而我上文說到的兩個ide他們之所以會那麼快,是因為他們並不渲染所有的文字,他們每次只渲染桌面顯示用的到的文字,其他的文字等你的scrollbar拉到對應地方的時候再渲染,這樣一來,每次需要渲染的文字可能就只有幾千個了,完全就能達到普通的需求
看那麼多答案只有 @佟dark為 答到圖形學點子上的。
印象不深,懶得去翻我的大學傷痕圖形學課本了,詳細說挺複雜,簡要答一下,如有錯誤歡迎指正。
1.jpg/jpeg打開速度問題,誠如 佟dark為 所答,jpg並不是一次性把所有信息都渲染並展示給你看。程序只是先找使用最快傳輸過來的數據,放棄一些細節,把圖片先渲染一部分,讓人眼能夠「大致識別出「一張圖片。然後再根據後續傳輸的圖片進一步完善細節,顯示出完整的圖片。
當你把網速限制在56k 然後打開一個大圖片網頁,你有很大概率看到一個jpg圖片從色塊馬賽克到逐漸清晰的過程。
有時候在2g網路下你用手機刷微博,經常會發現有些圖片只刷到了一半,剩下半部分是灰色的,而軟體卻認為圖片已經打開完成了,就像這樣:
圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖
圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖
圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖圖
圖圖圖圖圖圖圖圖圖圖圖圖圖圖□□□□□□□□
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
這就是只接收到了一部分圖片數據,計算機先把這一部分數據渲染出來了,但是還有另外一部分數據沒有傳輸或者傳輸錯誤,而因為一些原因程序認為數據已經傳輸完畢了所導致的錯誤。
2.你看到的5m txt文本,他實際上是一串的文字編碼,並不是你實際上能看到的字體文字。
在屏幕上顯示時,計算機會將文字與font文件夾的字體文件匹配,然後根據編碼去字體文件中查找對應的字形(這裡還分矢量字體和點陣圖字體,嫌麻煩先略過),最後再根據你文字軟體的排版信息把文字圖形渲染到對應的屏幕坐標。
雖然大部分點陣圖字體的像素位數只有1位(黑白01),但是由於在屏幕上顯示一個文字本身的像素量遠大於點陣圖的1個像素,所以這個過程的計算量通常是遠大於單純8位像素圖片的。
一個優秀的文字閱讀軟體通常也是只渲染你所看到的第一屏文字,然後再根據你的瀏覽進度依次渲染後面的內容。
說明打開文本的時候很可能沒有用vi
推薦閱讀:
※你在閱讀源代碼或設計文檔時,看到哪些驚艷的技巧?
※導師想要招收什麼樣的研究生?
※俄羅斯計算機相關專業高等院校教育及科研現狀是怎樣的?
※電腦重新分區並重裝了系統文件可以恢復啊嗎?
※為什麼人工智慧用Python?