首页 > 解决方案 > 添加字节到字节数组方法优化

问题描述

我有一个包含超过 200 000 个字符串的列表(每个值在十六进制中看起来像“0x01”)。我正在做的是循环列表中的每个值并将该字符串值转换为一个字节,然后将其添加到字节数组中。我遇到了一个问题 - 它持续时间太长(例如 200 000 个字符串持续 16 秒)。我在互联网上发现了这种方法,它向现有字节数组添加了一个字节,但这种方法似乎很慢:

private byte[] addByteToArray(byte[] bArray, byte newByte)
        {
            byte[] newArray = new byte[bArray.Length + 1];
            bArray.CopyTo(newArray, 1);
            newArray[0] = newByte;
            return newArray;
        }

你知道如何在几毫秒而不是几秒内让这个方法更快吗?提前感谢您的想法!

标签: c#

解决方案


我有一个包含超过 200 000 个字符串的列表(每个值在十六进制中看起来像“0x01”)。我正在做的是循环列表中的每个值并将该字符串值转换为一个字节,然后将其添加到字节数组中

所以你有这个:

List<String> listOfHexBytes = new List<String>() { "0x01", "0x02", "0x03", ... };

你想得到Byte[]吗?


不幸的是,.NET 没有简单的内置方法来解析 C 样式的十六进制数,所以这里有一个快速的方法(通过避免子字符串来避免 GC 堆分配):

static class Base16
{
        public static Byte GetNibble( Char hexDigit )
        {
            if( hexDigit >= 48 && hexDigit <=  57 ) return (Byte)( hexDigit - 48 ); // 0-9

            if( hexDigit >= 65 && hexDigit <=  90 ) return (Byte)( 10 + ( hexDigit - 65 ) ); // A-F

            if( hexDigit >= 97 && hexDigit <= 122 ) return (Byte)( 10 + ( hexDigit - 65 ) ); // a-f

            throw new ArgumentOutOfRangeException( nameof(hexDigit), hexDigit, "Value is not a hexadecimal digit character." );
        }

        public static Byte ParseCStyleByte( String s )
        {
            if( s.Length == 4 && s[0] == '0' && s[1] == 'x' )
            {
                Char h = s[2]; // high nibble
                Char l = s[3]; // low nibble
                
                Byte hb = GetNibble( h );
                Byte lb = GetNibble( h );
                return ( hb << 4 ) | lb;
            }
            else
            {
                throw new FormatException( "Value \"" + s + "\" is not a C-style byte." );
            }
        }
}

像这样使用:

Byte[] asByteArray = listOfHexBytes
    .Select( Base16.ParseCStyleByte )
    .ToArray();

虽然这会导致两个数组副本ToArray在输入具有已知长度时不会优化(Linq 有一些愚蠢的设计问题......),但这样做也可以:

Byte[] output = new Byte[ listOfHexBytes.Count ];
for( Int32 i = 0; i < output.Length; i++ )
{
    output[i] = Base16.ParseCStyleByte( listOfHexBytes[i] );
}

推荐阅读