C#?從?UTF-8?流中讀取字符串的正確方法及代碼詳解
?我們下面的代碼是從一個流 stream 中讀取 UTF-8 編碼的字符串。我們可以先考慮一下其中存在的潛在問題。
string ReadString(Stream stream) { var sb = new StringBuilder(); var buffer = new byte[4096]; int readCount; while ((readCount = stream.Read(buffer)) > 0) { var s = Encoding.UTF8.GetString(buffer, 0, readCount); sb.Append(s); } return sb.ToString(); }
問題出在:某些情況下返回的字符串與與原始編碼的字符串并不同。
例如,笑臉符號?? 有時會被解碼為 4 個未知字符:
編碼字符串: ??
解碼字符串: ????
我們知道:UTF-8 可以使用 1 到 4 個字節(jié)來表示一個 Unicode 字符,有關(guān)字符串編碼的知識可以參考 ??字符編碼??? 一文。
??Stream.Read??? 方法可以把從 1 到?? messageBuffer.Length??? 字節(jié)返回,這意味著緩沖區(qū)可能包含不完整的 UTF-8 字符。
一旦緩沖區(qū)中的最后一個字符的 UTF-8 編碼不完整,那么 ??Encoding.UTF8.GetString?? 就是轉(zhuǎn)換一個無效的 UTF-8 字符串。在這種情況下,該方法返回一個無效字符串,因為它無法猜測丟失的字節(jié)。
我們使用以下代碼演示以上行為:
var bytes = Encoding.UTF8.GetBytes("?"); // bytes = new byte[4] { 240, 159, 152, 138 } var sb = new StringBuilder(); // 模擬逐個字節(jié)地讀取數(shù)據(jù)流 for (var i = 0; i < bytes.Length; i++) { sb.Append(Encoding.UTF8.GetString(bytes, i, 1)); } Console.WriteLine(sb.ToString()); // "????" 代替了 "??" Encoding.UTF8.GetBytes(sb.ToString()); // new byte[12] { 239, 191, 189, 239, 191, 189, 239, 191, 189, 239, 191, 189 }
如何修復代碼
有多種方法可以修復代碼。
第一種方法:只有當你得到全部數(shù)據(jù)時,才將字節(jié)數(shù)組轉(zhuǎn)換為字符串。
string ReadString(Stream stream) { using var ms = new MemoryStream(); var buffer = new byte[4096]; int readCount; while ((readCount = stream.Read(buffer)) > 0) { ms.Write(buffer, 0, readCount); } return Encoding.UTF8.GetString(ms.ToArray()); }
第二種方法:可以把流包進一個具有正確編碼的 StreamReader 對象中。
string ReadString(Stream stream) { using var sr = new StreamReader(stream, Encoding.UTF8); return sr.ReadToEnd(); }
另外,還可以使用System.Text.Decoder類來正確解碼緩沖區(qū)內(nèi)的字符。在需要性能的情況下,可以使用PipeReader、Rune類來以內(nèi)存優(yōu)化的方式讀取數(shù)據(jù)。
到此這篇關(guān)于C#?從?UTF-8?流中讀取字符串的正確方法及代碼詳解的文章就介紹到這了,更多相關(guān)C#?從?UTF-8?流中讀取字符串的正確方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析C#中StringBuilder類的高效及與String的對比
StringBuilder類所創(chuàng)造出來的字符串對象在拼接操作等方面比普通的string類往往要高效很多,這是它們在內(nèi)存劃分方式上的不同所決定的,下面就來淺析C#中StringBuilder類的高效及與String的對比2016-05-05C# 控件屬性和InitializeComponent()關(guān)系案例詳解
這篇文章主要介紹了C# 控件屬性和InitializeComponent()關(guān)系案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-08-08C# 在PDF文檔中創(chuàng)建表格的實現(xiàn)方法
表格能夠一目了然的讓用戶看到數(shù)據(jù)信息,使信息顯得有條理化,那么在pdf類型的文檔中如何來添加表格并對表格進行格式化操作呢?下面小編給大家?guī)砹薈# 在PDF文檔中創(chuàng)建表格的實現(xiàn)方法,需要的朋友參考下吧2017-12-12C#中調(diào)用Windows API的技術(shù)要點說明
本篇文章主要是對C#中調(diào)用Windows API的技術(shù)要點進行了詳細的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01