目錄
問題緣由
背后原理
(資料圖)
C#代碼示例
總結(jié)
由于公司需求,需要讀取游戲Redis數(shù)據(jù)做內(nèi)外網(wǎng)數(shù)據(jù)遷移,沒有與游戲組過多的溝通。 使用的數(shù)據(jù)類型是Hash, key是string,value是byte[]。以前對(duì)于編碼的理解是:計(jì)算機(jī)底層存儲(chǔ)的永遠(yuǎn)是01的二進(jìn)制數(shù)據(jù),編碼是一種對(duì)于計(jì)算機(jī)二進(jìn)制數(shù)據(jù)的字符映射,也就是約定好哪個(gè)值對(duì)應(yīng)哪個(gè)字符。是為了便于在顯示器上展示。
那么基于這個(gè)理解,我就以為 不需要關(guān)心存儲(chǔ)的數(shù)據(jù)類型,因?yàn)槲也恍枰玫綌?shù)據(jù),我只是負(fù)責(zé)做數(shù)據(jù)的搬運(yùn)。于是我用的是HGetAsync方法去讀的字符串。然后HSetAsync把數(shù)據(jù)存到另一個(gè)Redis。結(jié)果發(fā)現(xiàn)數(shù)據(jù)發(fā)生了編碼?;谖疑线厡?duì)于編碼的理解,也就是按照不同的編碼讀取字符串,只是顯示器上會(huì)亂碼,但是底層的01二進(jìn)制沒有發(fā)生變化,這次問題打破了我的認(rèn)知。
背后原理當(dāng)一個(gè)byte[]在計(jì)算機(jī)中存儲(chǔ)時(shí),它就是以二進(jìn)制形式保存的。如果這個(gè)byte[]中的每一個(gè)字節(jié)代表的是ASCII碼(一個(gè)字節(jié)表示一個(gè)字符),那么它在不同的編碼下讀取應(yīng)該沒有問題。但是,如果它代表的是Unicode字符集(UTF-8和UTF-16等),那么在不同的編碼下讀取就會(huì)發(fā)生問題。因?yàn)椴煌木幋a方式對(duì)存儲(chǔ)方式和字節(jié)長度都有不同的要求。
以UTF-8為例,它對(duì)不同字符分配的位數(shù)不同。對(duì)于ASCII字符,UTF-8使用一個(gè)字節(jié)表示,而對(duì)于其他字符,它需要兩個(gè)字節(jié)、三個(gè)字節(jié)或四個(gè)字節(jié)來表示。因此,在按照UTF-8格式讀取一個(gè)byte[]時(shí),如果它的編碼確實(shí)是UTF-8,那么就可以讀取正確的字符。但是,如果重新以UTF-8的格式存儲(chǔ)它時(shí),就會(huì)按照UTF-8的編碼方式重新把這個(gè)字符轉(zhuǎn)換成二進(jìn)制。如果這個(gè)字符之前的編碼不是UTF-8,那么它在轉(zhuǎn)換為UTF-8的二進(jìn)制時(shí),就會(huì)變成不同的值,因此數(shù)據(jù)也就變了。
C#代碼示例var data = Encoding.UTF32.GetBytes("愛");var word = Encoding.UTF8.GetString(data);var word1 = Encoding.UTF32.GetString(data);File.WriteAllText($@"{AppDomain.CurrentDomain.BaseDirectory}/code.txt", word);File.WriteAllText($@"{AppDomain.CurrentDomain.BaseDirectory}/code1.txt", word1);foreach (var d in File.ReadAllBytes($@"{AppDomain.CurrentDomain.BaseDirectory}/code.txt")){ Console.WriteLine(d);}Console.WriteLine("------------");foreach (var d in File.ReadAllBytes($@"{AppDomain.CurrentDomain.BaseDirectory}/code1.txt")){ Console.WriteLine(d);}
例如,我們有一個(gè)Unicode字符“愛”,其二進(jìn)制表示為:0000 0100 1110 0111。按照UTF-8編碼的規(guī)則,在存儲(chǔ)這個(gè)字符時(shí),我們需要使用3個(gè)字節(jié)的二進(jìn)制數(shù)據(jù):1110XXXX 10XXXXXX 10XXXXXX(X表示對(duì)應(yīng)字符的二進(jìn)制數(shù)據(jù)的高位)
我們將其存儲(chǔ)到一個(gè)byte[]中,再將其存儲(chǔ)到文件中。然后按照UTF-8的格式讀取,解析出Unicode字符“愛”,再將其按照UTF-8的格式存儲(chǔ)回文件。這時(shí),由于使用了UTF-8編碼,我們需要將Unicode字符“愛”轉(zhuǎn)換為UTF-8編碼的二進(jìn)制數(shù)據(jù),即,使用3個(gè)字節(jié)的二進(jìn)制數(shù)據(jù):11100100 10101110 10011111。
通過運(yùn)行代碼,可以看到,由于存儲(chǔ)使用了UTF-8編碼,而讀取和重新存儲(chǔ)又使用了UTF-8編碼,因此二進(jìn)制數(shù)據(jù)發(fā)生了變化。
總結(jié)當(dāng)一個(gè)byte[]在計(jì)算機(jī)中存儲(chǔ)時(shí),它就是以二進(jìn)制形式保存的。如果這個(gè)byte[]中的每一個(gè)字節(jié)代表的是ASCII碼(一個(gè)字節(jié)表示一個(gè)字符),那么它在不同的編碼下讀取應(yīng)該沒有問題。但是,如果它代表的是Unicode字符集(UTF-8和UTF-16等),那么在不同的編碼下讀取就會(huì)發(fā)生問題。
?標(biāo)簽:
Copyright © 2015-2022 太平洋獸藥網(wǎng) 版權(quán)所有 備案號(hào):豫ICP備2022016495號(hào)-17 聯(lián)系郵箱:93 96 74 66 9@qq.com