将可能以null结尾的ascii byte 转换为字符串的最快方法?

我需要将一个(可能)以null结尾的ascii字节数组转换为C#中的字符串,我发现这样做的最快方法是使用下面显示的UnsafeAsciiBytesToString方法。 此方法使用String.String(sbyte *)构造函数,该构造函数在其备注中包含警告:

“假设value参数指向一个数组,该数组表示使用默认ANSI代码页编码的字符串(即Encoding.Default指定的编码方法)。

注意: *因为默认的ANSI代码页是系统相关的,所以此构造函数从相同的有符号字节数组创建的字符串可能在不同的系统上有所不同。 * ……

*如果指定的数组不以null结尾,则此构造函数的行为取决于系统。 例如,这种情况可能会导致访问冲突。 *

现在,我很肯定字符串编码的方式永远不会改变……但是我的应用程序运行的系统上的默认代码页可能会改变。 那么,为什么我不应该为使用String.String(sbyte *)而尖叫呢?

using System; using System.Text; namespace FastAsciiBytesToString { static class StringEx { public static string AsciiBytesToString(this byte[] buffer, int offset, int maxLength) { int maxIndex = offset + maxLength; for( int i = offset; i < maxIndex; i++ ) { /// Skip non-nulls. if( buffer[i] != 0 ) continue; /// First null we find, return the string. return Encoding.ASCII.GetString(buffer, offset, i - offset); } /// Terminating null not found. Convert the entire section from offset to maxLength. return Encoding.ASCII.GetString(buffer, offset, maxLength); } public static string UnsafeAsciiBytesToString(this byte[] buffer, int offset) { string result = null; unsafe { fixed( byte* pAscii = &buffer[offset] ) { result = new String((sbyte*)pAscii); } } return result; } } class Program { static void Main(string[] args) { byte[] asciiBytes = new byte[]{ 0, 0, 0, (byte)'a', (byte)'b', (byte)'c', 0, 0, 0 }; string result = asciiBytes.AsciiBytesToString(3, 6); Console.WriteLine("AsciiBytesToString Result: \"{0}\"", result); result = asciiBytes.UnsafeAsciiBytesToString(3); Console.WriteLine("UnsafeAsciiBytesToString Result: \"{0}\"", result); /// Non-null terminated test. asciiBytes = new byte[]{ 0, 0, 0, (byte)'a', (byte)'b', (byte)'c' }; result = asciiBytes.UnsafeAsciiBytesToString(3); Console.WriteLine("UnsafeAsciiBytesToString Result: \"{0}\"", result); Console.ReadLine(); } } } 

有什么理由不使用String(sbyte*, int, int)构造函数? 如果你已经找出了你需要的缓冲区的哪一部分,其余部分应该很简单:

 public static string UnsafeAsciiBytesToString(byte[] buffer, int offset, int length) { unsafe { fixed (byte* pAscii = buffer) { return new String((sbyte*)pAscii, offset, length); } } } 

如果你需要先看看:

 public static string UnsafeAsciiBytesToString(byte[] buffer, int offset) { int end = offset; while (end < buffer.Length && buffer[end] != 0) { end++; } unsafe { fixed (byte* pAscii = buffer) { return new String((sbyte*)pAscii, offset, end - offset); } } } 

如果这确实是一个ASCII字符串(即所有字节都小于128),那么除非你有一个特别奇怪的默认代码页,而不是基于ASCII,否则代码页问题不应成为问题。

出于兴趣,您是否真的已经分析了您的应用程序以确保这确实是瓶颈? 你肯定需要绝对最快的转换,而不是更可读的转换(例如使用Encoding.GetString进行适当的编码)?

Oneliner(假设缓冲区实际上包含一个格式良好的空终止字符串):

 String MyString = Encoding.ASCII.GetString(MyByteBuffer).TrimEnd((Char)0); 
 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TestProject1 { class Class1 { static public string cstr_to_string( byte[] data, int code_page) { Encoding Enc = Encoding.GetEncoding(code_page); int inx = Array.FindIndex(data, 0, (x) => x == 0);//search for 0 if (inx >= 0) return (Enc.GetString(data, 0, inx)); else return (Enc.GetString(data)); } } } 
 s = s.Substring(0, s.IndexOf((char) 0)); 

考虑的一种可能性:检查默认代码页是否可接受,并使用该信息在运行时选择转换机制。

这也可以考虑字符串是否实际上是空终止的,但是一旦你完成了这一点,当然,速度增加了我的消失。

我不确定速度,但我发现在编码之前使用LINQ删除空值最容易:

 string s = myEncoding.GetString(bytes.TakeWhile(b => !b.Equals(0)).ToArray()); 

一种简单/安全/快速的方法,使用.NET类System.Text.Encoding将byte []对象转换为包含ASCII等效字符串的字符串,反之亦然。 该类有一个返回ASCII编码器的静态函数:

从String到byte []:

 string s = "Hello World!" byte[] b = System.Text.Encoding.ASCII.GetBytes(s); 

从byte []到string:

 byte[] byteArray = new byte[] {0x41, 0x42, 0x09, 0x00, 0x255}; string s = System.Text.Encoding.ASCII.GetString(byteArray); 

这有点难看但你不必使用不安全的代码:

 string result = ""; for (int i = 0; i < data.Length && data[i] != 0; i++) result += (char)data[i];