JS幻想 讀取二進(jìn)制文件第1/2頁
畢竟腳本的理念僅僅是用來處理一些簡(jiǎn)單的交互的,對(duì)于處理字節(jié)流之類的復(fù)雜問題完全不該是腳本的職責(zé)。不過作為一種探索,我們還是可以挖掘下其中的樂趣。當(dāng)然,首先要明確的是,對(duì)于二進(jìn)制的讀取JS確實(shí)是無能為力的,不過我們可以來模擬,以達(dá)到相同的效果,下面就跟著我來吧。
比如現(xiàn)在想要做個(gè)推箱子的小游戲,共200關(guān)。這時(shí)唯一值得考慮到事就出現(xiàn)了:把這200關(guān)地圖數(shù)據(jù)保存在何處?如果直接硬塞在一個(gè)腳本文件里似乎顯得太大,或者單獨(dú)保存在一個(gè)文件里,但是用什么格式。。。不過對(duì)于推箱子游戲來說簡(jiǎn)單的文本格式也夠了,但對(duì)于一些地圖較復(fù)雜的也許就會(huì)使用BASE64編碼,然后由客戶端的HTTP組件下載下來解碼使用。BASE64編碼在JS中還是很常用的,畢竟它不受任何的環(huán)境限制,能夠處理字符串就行。
既然有個(gè)BASE64,那為什么就不能有BASE128,BASE256了呢?如果能實(shí)現(xiàn)“BASE256”,豈不就是二進(jìn)制字節(jié)流了?如果真可以如此,那這種方法早就流傳開了,還留著那么多的BASE64做什么:)畢竟這是字符串,而不叫字節(jié)串,那肯定是有區(qū)別的。不妨把一個(gè)二進(jìn)制的文件,當(dāng)作文本文件讀取回來試試,很快你就會(huì)發(fā)現(xiàn)超過一旦文件中出現(xiàn)127(0x7F)以上的字符,馬上就出錯(cuò)了;如果存在個(gè)0x00字節(jié)的話,后面的內(nèi)容都會(huì)蕩然無存,這意味著256個(gè)字符中能夠利用的還不到一半。
然而,可別忘了這個(gè)測(cè)試使用的僅僅是最基本的ASCII編碼,對(duì)于功能強(qiáng)大的XMLHTTP支持的也絕不僅限于如此,那么就試試Unicode字符會(huì)怎樣。在記事本隨便輸幾個(gè)字符,保存為Unicode格式的文本文件。這時(shí)用XMLHTTP讀取,顯示出來的與記事本里的一模一樣,但是再用16進(jìn)制編輯器打開此文件時(shí),就大不相同了。在文件的開頭出現(xiàn)了FF FE兩字節(jié),后面的每個(gè)內(nèi)容都是由一個(gè)0隔開。畢竟這是16位的Unicode字符,除了基本的ASCII外,還要保存各國的文字。例如一個(gè)中文就占用了2個(gè)字節(jié),而英文數(shù)字仍然占用2字節(jié),只是高位由0填充罷了(注意高位字節(jié)是在低位字節(jié)后面的)。
XMLHTTP能夠成功顯示出來就說明Unicode還是支持的。現(xiàn)在試著修改文件里面的數(shù)據(jù),看看超過了那些范圍才會(huì)出錯(cuò)。把數(shù)據(jù)修改成如下:FFFE 0001 0203 7F00 8000 8100 FF00 FFFF。用XMLHTTP測(cè)試,雖然顯示的都是亂碼,但并沒出錯(cuò),返回的字符串用charCodeAt(i)及toString(16)方法一試,原形畢露!幾經(jīng)測(cè)試,Unicode并不像ASCII那樣有范圍限制,但唯獨(dú)一個(gè)例外:0x0000!
眾所周知,0x00就是ASCII的結(jié)束標(biāo)志。但到了Unicode的世界里一切都是16位的,因此字符尾也成了0x0000。到了這里似乎有點(diǎn)遺憾,但接著的目標(biāo)很明確:如果能夠去掉文件中的0x0000,并在之前加上0xFEFF,就能夠讓JavaScript讀取了。
去掉以及恢復(fù),不妨就稱他編碼與解碼吧。編碼的方法就見智見仁了,最簡(jiǎn)單的辦法就是記錄下每個(gè)0x0000的位置,然后除去;在客戶端按照記錄的位置再復(fù)原回去。雖然簡(jiǎn)單,但也別忘了,0x00在二進(jìn)制文件中是相當(dāng)多的,即便是0x0000也是。這樣光是記錄他們的內(nèi)容就有很多,顯然不是很好。既然說到要記錄,為何一定要記錄0x0000的位置?反過來想,我們應(yīng)該記錄這個(gè)文件中出現(xiàn)次數(shù)最少的字符,以及它的位置,然后把0x0000的地方替換成這個(gè)字符;解碼的時(shí)候一旦出現(xiàn)這個(gè)字符,但當(dāng)前位置又不在記錄中,就可以確定這就是個(gè)0x0000。事實(shí)上,在64K以下的文件中肯定有個(gè)字符根本就不會(huì)出現(xiàn)的(為什么仔細(xì)考慮下就明白),即使是在64K以上,還是有非常多的文件不存在某個(gè)字符的。畢竟一個(gè)Unicode字符有65536之多,很少有文件會(huì)把他們?nèi)加蒙?,除非是個(gè)冗余極小的壓縮文件,但也不會(huì)很多。
到此,編碼解碼思路已明了,剩下自然是實(shí)現(xiàn)他們。
剛才提到了源文件中出現(xiàn)最少(甚至是沒有)的Unicode字符,不妨就稱作key
首先來定義新生成的二進(jìn)制文件頭格式:
00 01 0xFEFF。 Unicode文件頭,這是必須的
02 03 Key值。 為了不讓0x0000成為Key,在尋找的過程中忽略0x0000
03 04 Key出現(xiàn)的次數(shù)+1。 +1是為了避免該位置出現(xiàn)0x0000,后面的也都一樣
05 06
07 08 第1個(gè)Key的位置 用4字節(jié)保存每個(gè)Key的位置。
09 0A
0B 0C 。。。
0D 0E
0F 10 第n個(gè)Key的位置
11 12 文件數(shù)據(jù)內(nèi)容。。。
相關(guān)文章
BootStrap數(shù)據(jù)表格實(shí)例代碼
本文通過實(shí)例代碼給大家分享了BootStrap數(shù)據(jù)表格的相關(guān)知識(shí),感興趣的朋友一起看看吧2017-09-09
JavaScript查看代碼運(yùn)行效率console.time()與console.timeEnd()用法
今天小編就為大家分享一篇關(guān)于JavaScript查看代碼運(yùn)行效率console.time()與console.timeEnd()用法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-01-01
JS動(dòng)態(tài)添加Table的TR,TD實(shí)現(xiàn)方法
這篇文章主要介紹了JS動(dòng)態(tài)添加Table的TR,TD實(shí)現(xiàn)方法,涉及js針對(duì)Table中TR、TD節(jié)點(diǎn)的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01
js實(shí)現(xiàn)頁面導(dǎo)航層級(jí)指示效果
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)頁面導(dǎo)航層級(jí)指示效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
ECMAScript5中的對(duì)象存取器屬性:getter和setter介紹
這篇文章主要介紹了ECMAScript5中的對(duì)象屬性存取器:getter和setter介紹,事實(shí)上在除ie外最新主流瀏覽器的實(shí)現(xiàn)中,任何一個(gè)對(duì)象的鍵值都可以被getter和setter方法所取代,這被稱之為“存取器屬性”,需要的朋友可以參考下2014-12-12
JavaScript 獲取 URL 中參數(shù)值的方法
本文將詳細(xì)介紹幾種在 JavaScript 中獲取 URL 參數(shù)值的方法,包括現(xiàn)代瀏覽器支持的 URLSearchParams、正則表達(dá)式解析以及自定義函數(shù)解析方案,并討論各自的優(yōu)缺點(diǎn)及適用場(chǎng)景,感興趣的朋友一起看看吧2025-04-04
詳解TS對(duì)象擴(kuò)展運(yùn)算符和rest運(yùn)算符
這篇文章主要介紹了詳解TS對(duì)象擴(kuò)展運(yùn)算符和rest運(yùn)算符,對(duì)TypeScript感興趣的同學(xué),可以參考下2021-05-05
僅IE不支持setTimeout/setInterval函數(shù)的第三個(gè)以上參數(shù)
setTimeout/setInterval,這兩個(gè)函數(shù)相信前端開發(fā)同學(xué)都很熟悉。它們?cè)诜荌E(6-9)瀏覽器中還可以如下使用2011-05-05
JavaScript算法實(shí)例之求二叉樹從根到葉的所有路徑和
如果你希望求某一特定路徑(例如從根到葉子)上數(shù)字的和,那么問題就轉(zhuǎn)變?yōu)榱恕扒蠖鏄鋸母饺~的所有路徑和”,所以本文給大家介紹了如何使用JavaScript求二叉樹從根到葉的所有路徑和,需要的朋友可以參考下2023-10-10

