[英]Read UTF-8 encoded string from io.Reader
我正在寫一個帶有TCP套接字的小型通信協議。 我能夠讀寫基本數據類型,例如整數,但是我不知道如何從字節片中讀取UTF-8編碼的字符串。
協議客戶端是用Java編寫的,服務器是Go。
根據我的閱讀:GO符文為32位長,而UTF-8字符為1至4個字節長,這使得無法簡單地將字節片轉換為String。
我想知道如何讀寫這個UTF-8流。
注意我有按時讀取字節的字節緩沖區長度。
首先講一些理論:
rune
代表Unicode代碼點-一個分配給Unicode中特定字符的數字。 這是uint32
的別名。 這如何映射到Go數據類型:
[]byte
和string
存儲一系列字節 (Go中的一個byte
是uint8
的別名)。
主要區別在於字符串是不可變的,因此您可以
b := make([]byte, 2) b[0] = byte('a') b[1] = byte('z')
你不能
var s string s[0] = byte('a')
后一個事實甚至由於無法顯式設置字符串長度而得到強調(就像在虛構的s := make(string, 10)
)。
string
和[]rune
之間的類型轉換將string
解析為一系列UTF-8編碼的代碼點,並產生其中的一部分。 反向類型轉換從符文切片中提取Unicode代碼點,並生成UTF-8編碼的字符串。 range
循環遍歷包含字符串的Unicode代碼點, 而不僅僅是字節。 Go還提供了string
和[]byte
以及返回之間的類型轉換。 現在回想一下,字符串是只讀的,而字節片不是。 這意味着像
b := make([]byte, 1000)
io.ReadFull(r, b)
s := sting(b)
無論您將切片轉換為字符串還是反向轉換,始終都會復制數據。 這浪費了空間,但是是類型安全的,並強制了語義。
現在回到手頭的任務。
如果您使用較小的字符串並且沒有內存壓力,則只需將io.Read()
(或其他)填充的字節片轉換為字符串。 確保重用您用來讀取數據的切片,以減輕垃圾收集器的壓力-也就是說,不要為每個新讀取分配新的切片,因為您將要復制存儲在其上的數據。將代碼讀取為字符串。
最后,如果你絕對必須不復制數據(比如,你在處理多兆字節的字符串,你有嚴格的內存需求),你可以嘗試用內存不安全的工作中發揮骯臟的把戲- 在這里是一個例子如何將內存從字節片移植到字符串。 請注意,如果您恢復到類似這樣的狀態,則必須非常了解它可以隨Go的任何新版本一起自由破解,甚至不能保證它可以正常工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.