Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将可能以null结尾的ascii字节[]转换为字符串的最快方法?_C#_.net_String_Ascii - Fatal编程技术网

C# 将可能以null结尾的ascii字节[]转换为字符串的最快方法?

C# 将可能以null结尾的ascii字节[]转换为字符串的最快方法?,c#,.net,string,ascii,C#,.net,String,Ascii,我需要将(可能)以null结尾的ascii字节数组转换为C#中的字符串,我发现最快的方法是使用下面所示的unsafeascibytestostring方法。此方法使用String.String(sbyte*)构造函数,该构造函数的备注中包含警告: 假定value参数指向一个数组,该数组表示使用默认ANSI代码页(即encoding.default指定的编码方法)编码的字符串 注意:*由于默认的ANSI代码页依赖于系统,因此此构造函数从相同的带符号字节数组创建的字符串可能在不同的系统上有所不同。*

我需要将(可能)以null结尾的ascii字节数组转换为C#中的字符串,我发现最快的方法是使用下面所示的unsafeascibytestostring方法。此方法使用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();
        }
    }
}
使用系统;
使用系统文本;
命名空间FastAsciByteStoString
{
静态类StringEx
{
公共静态字符串AsciByteStoString(此字节[]缓冲区,int偏移量,int maxLength)
{
int maxIndex=偏移量+最大长度;
对于(int i=offset;i
有什么理由不使用
字符串(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);
       }
    }
}
公共静态字符串unsafeascibytestostring(字节[]缓冲区,int偏移量)
{
int end=偏移量;
while(end
如果这确实是一个ASCII字符串(即所有字节都小于128个),那么代码页问题就不应该成为问题,除非您有一个特别奇怪的默认代码页,它不是基于ASCII的


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

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


这还可以考虑字符串实际上是否以null结尾,但一旦这样做,当然,速度就会消失。

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

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

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

string result = "";
for (int i = 0; i < data.Length && data[i] != 0; i++)
   result += (char)data[i];
字符串结果=”;
对于(int i=0;i
使用.NET类System.Text.Encoding,将byte[]对象转换为包含其ASCII等价物的字符串,或将其转换为包含其ASCII等价物的字符串的简单/安全/快速方法。该类具有返回ASCII编码器的静态函数:

从字符串到字节[]:

string s = "Hello World!"
byte[] b = System.Text.Encoding.ASCII.GetBytes(s);
从字节[]到字符串:

byte[] byteArray = new byte[] {0x41, 0x42, 0x09, 0x00, 0x255};
string s = System.Text.Encoding.ASCII.GetString(byteArray);
Oneliner(假设缓冲区实际上包含一个格式良好的空终止字符串):


为了完整起见,您还可以使用.NET framework的内置方法来执行此操作:

var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
    return Marshal.PtrToStringAnsi(handle.AddrOfPinnedObject());
}
finally
{
    handle.Free();
}
优点:

  • 它不需要不安全的代码(即,您也可以在VB.NET中使用此方法)和
  • 如果改用
    Marshal.PtrToStringUni
    ,它也适用于“宽”(UTF-16)字符串

哎哟,我刚刚意识到了一件事……在使用String.String(sbyte*)时,我没有办法指定最大长度,这基本上意味着使用构造函数读取环形缓冲区的结果会失败,因为它可能会持续读取超过最大长度的数据到下一段!谢谢你的回复。我没有使用String(sbyte*,int,int),因为它不会在找到第一个空值时停止,而是将每个空值转换为一个空格,就像Encoding.ASCII.GetString()一样。哦,它也不是瓶颈或任何东西。我只是个书呆子,没有更好的事可做
byte[] byteArray = new byte[] {0x41, 0x42, 0x09, 0x00, 0x255};
string s = System.Text.Encoding.ASCII.GetString(byteArray);
String MyString = Encoding.ASCII.GetString(MyByteBuffer).TrimEnd((Char)0);
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
    return Marshal.PtrToStringAnsi(handle.AddrOfPinnedObject());
}
finally
{
    handle.Free();
}