簡體   English   中英

從io.Reader讀取UTF-8編碼的字符串

[英]Read UTF-8 encoded string from io.Reader

我正在寫一個帶有TCP套接字的小型通信協議。 我能夠讀寫基本數據類型,例如整數,但是我不知道如何從字節片中讀取UTF-8編碼的字符串。

協議客戶端是用Java編寫的,服務器是Go。

根據我的閱讀:GO符文為32位長,而UTF-8字符為1至4個字節長,這使得無法簡單地將字節片轉換為String。

我想知道如何讀寫這個UTF-8流。

注意我有按時讀取字節的字節緩沖區長度。

首先講一些理論:

  • Go中的rune代表Unicode代碼點-一個分配給Unicode中特定字符的數字。 這是uint32的別名。
  • UTF-8是Unicode 編碼 —一種表示 Unicode代碼點的格式,用於存儲和傳輸。 UTF-8可能使用1到4個字節來編碼單個代碼點。

這如何映射到Go數據類型:

  • []bytestring存儲一系列字節 (Go中的一個byteuint8的別名)。

    主要區別在於字符串是不可變的,因此您可以

     b := make([]byte, 2) b[0] = byte('a') b[1] = byte('z') 

    你不能

     var s string s[0] = byte('a') 

    后一個事實甚至由於無法顯式設置字符串長度而得到強調(就像在虛構的s := make(string, 10) )。

  • 盡管Go中的字符串包含抽象字節(例如,您可以自由存儲使用Windows-1252編碼的字符),但某些Go語句和類型轉換會將字符串解釋為以UTF-8編碼,尤其是:
    • 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM