国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

字符編碼問題記錄

doodlewind / 697人閱讀

摘要:需求問題需要對序列化以后的對象中的在中進行存取由于聲稱只支持作為暴露出來的最基本的數據類型形式的存取所以需要在存取前后將與互相轉換發現從出來的跟之前的不一樣即使強制指定了一致的編碼解碼方式結果仍不符合預期猜測嘗試懷疑是系統的默認編碼方式與解

需求&問題

需要對序列化以后的對象 (java中的byte[]) 在redis中進行存取
由于redis聲稱只支持String(作為redis暴露出來的最基本的數據類型)形式的存取 (ref: https://redis.io/topics/internals, https://redis.io/topics/internals )
所以需要在存取前后將byte[]與String互相轉換

發現從string decode出來的byte[]跟encode之前的byte[]不一樣
即使強制指定了一致的編碼解碼方式, 結果仍不符合預期

byte[] origin = eh.toBytes(event); // serialized event

String str1 = new String(origin);
byte[] new1 = str1.getBytes();
System.out.println(Arrays.equals(origin, new1));
// output: false

String str2 = new String(origin, StandardCharsets.US_ASCII);
byte[] new2 = str2.getBytes(StandardCharsets.US_ASCII);
System.out.println(Arrays.equals(origin, new2));
// output: false

String str3 = new String(origin, StandardCharsets.UTF_8);
byte[] new3 = str3.getBytes(StandardCharsets.UTF_8);
System.out.println(Arrays.equals(origin, new3));
// output: false
猜測&嘗試

懷疑是系統的默認編碼方式與解碼時指定的不同, 如上所示 強制指定后未果

照理說編碼解碼的算法是對稱的, 對一個byte[]編碼解碼后的到byte[]理應也是一樣的. 嘗試使用apache的StringUtils編碼解碼, 結果徒然

原因&解釋

經搜索試驗后發現原因既與這個byte[]本身有關又與編碼方式有關:

該場景中event結構中包含一個UUID, 未序列化前在java中以一個長度為32個字符的字符串表示, 例子“ce4326f3694b479dad472f250b975ee7”, 序列化后在java中為一個長度16個字節的字節數組

為了節省空間, UUID序列化的規則為: 依次將每2個字符視為一個16進制數, 將其轉成對應的10進制數, 并寫入一個字節空間中. 總共占16字節

一個字節占8個位, 范圍為 0000 0000 ~ 1111 1111 (2進制), 00 ~ FF (16進制), 0 ~ 255 (10進制). java里的一個byte變量也能表示256種狀態 (剛好相當于16進制數) 然而它的值(10進制)的范圍是 -128 ~ 127, 而不是 0 ~ 255. 其中 -128 ~ -1 對應 128 ~ 255

這就導致了將序列化成byte[]以后的event encode成String的時候出現問題, 因為常用的 ASCII, UTF-8等字符集中均沒有負數對應的字符. 這意味著event中UUID部分中 80 ~ FF 的值都會被無效encode

比如ASCII中這些值會默認被encode成’?’ (字符), decode成java的byte的時候就變成了63(10進制) ; 在UTF-8中更常見的情況是byte[]中的 byte序列不合法 (Invalid byte sequences) 也就是說該序列所代表的值不在UTF-8字符集支持的index范圍之內. 導致了原始的byte[]和經過encode decode后的byte[]不同

Reference:
java - Encoding and decoding UTF-8 byte arrays from and to strings - Stack Overflow
java - Why are the lengths different when converting a byte array to a String and then back to a byte array? - Stack Overflow

解決方案

使用Base64安全的轉換二進制與字符串, 但會使payload增加33%, 原因點此

使用 Latin-1 編碼, 最大缺點是解碼時對于UTF-8不兼容

直接傳輸二進制數據(java中的byte[]), 具體方式為使用jedis中的BinaryClient類, 其中的方法支持 byte[] 類型的參數

For anyone who’s curious enough:

顯然方案3是比較理想的. 看到這里記性好的人不免發出疑問: 開頭不是說redis只支持String形式的存取嗎?

這里引用一段jedis的文檔:

A note about String and Binary - what is native?

Redis/Jedis talks a lot about Strings. And here http://redis.io/topics/internals it says Strings are the basic building block of Redis. However, this stress on strings may be misleading. Redis" "String" refer to the C char type (8 bit), which is incompatible with Java Strings (16-bit). Redis sees only 8-bit blocks of data of predefined length, so normally it doesn"t interpret the data (it"s "binary safe"). Therefore in Java, byte[] data is "native", whereas Strings have to be encoded before being sent, and decoded after being retrieved by the SafeEncoder. This has some minor performance impact. In short: if you have binary data, don"t encode it into String, but use the binary versions.

上文提到其實redis官方文檔中多次提到的string是一種誤導, 原來redis所說的”String”指的是它的實現語言C中的char (8bit), 對應java中的byte (8bit), 而不是java中的String或char (16bit). Redis只按8位8位地去裸讀數據, 而不去解析(所謂的”二進制安全”). 所以, 從java的角度看redis, byte[]類型才是”原生”的

Redis實現中“String”的源碼:

struct sdshdr {
    long len;
    long free;
    char buf[];
};

后來想了下, 從傳輸層面/角度來講, 根本就沒有什么類型, 都是1 0. 應時時提醒自己跳出問題之外, 從源頭思考, 避免陷入本本主義

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66534.html

相關文章

  • 你真的了解 Unicode 和 UTF-8 嗎?

    摘要:編碼就是為了解決編碼的問題而生的,它擴展自基本多文種平面中,與編碼完全一致,使用兩個字節表示到范圍使用個字節表示編碼的市場份額和比很小,在頁面中只占。 引言 一直以來總是對 unicode, UTF-8 等編碼知識懵懵懂懂的,尤其是在做項目過程中只要涉及到幾個編碼之間的轉換,都得到網上搜索一番,根據別人的經驗照葫蘆畫瓢,才能解決問題,但是私底下卻完全不懂在做什么。 我再也不愿意重復這種...

    littlelightss 評論0 收藏0
  • 你真的了解 Unicode 和 UTF-8 嗎?

    摘要:編碼就是為了解決編碼的問題而生的,它擴展自基本多文種平面中,與編碼完全一致,使用兩個字節表示到范圍使用個字節表示編碼的市場份額和比很小,在頁面中只占。 引言 一直以來總是對 unicode, UTF-8 等編碼知識懵懵懂懂的,尤其是在做項目過程中只要涉及到幾個編碼之間的轉換,都得到網上搜索一番,根據別人的經驗照葫蘆畫瓢,才能解決問題,但是私底下卻完全不懂在做什么。 我再也不愿意重復這種...

    JellyBool 評論0 收藏0
  • 你真的了解 Unicode 和 UTF-8 嗎?

    摘要:編碼就是為了解決編碼的問題而生的,它擴展自基本多文種平面中,與編碼完全一致,使用兩個字節表示到范圍使用個字節表示編碼的市場份額和比很小,在頁面中只占。 引言 一直以來總是對 unicode, UTF-8 等編碼知識懵懵懂懂的,尤其是在做項目過程中只要涉及到幾個編碼之間的轉換,都得到網上搜索一番,根據別人的經驗照葫蘆畫瓢,才能解決問題,但是私底下卻完全不懂在做什么。 我再也不愿意重復這種...

    afishhhhh 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<