控制byte []数组的索引

时间:2014-07-10 08:46:24

标签: c# arrays

是否可以控制byte[]数组中的索引位置?在下面的代码中,我期望value1的返回值进入join的前七个字节,value2的返回值依次进入8 9 10 11位置。但这不会发生。前七个字节丢失,因为索引始终位于0位置。如何控制指数位置?

static void Main(string[] args)
    {
        byte[] join = new byte[15];
        join = value1(); //seven byte enters. 
        join = value2(); //next four byte enters.
                               // 'join' should now have eleven bytes. 
        string a = Encoding.UTF8.GetString(join);
        Console.WriteLine(a);
        Console.ReadLine();
    }

    public static byte[] value1() 
    {

        string first = "welcome";
        byte[] f = Encoding.UTF8.GetBytes(first);
        return f;// seven byte returning.

    }

    public static byte[] value2() 
    {
        string second = "home";
        byte[] s = Encoding.UTF8.GetBytes(second);
        return s;//four byte returning.
    }

我知道可以使用Array.Copy()Buffer.BlockCopy()重新组织代码。但是,如果代码运行100,000次或更多,这两种方法都很耗时。我期待避免这两种方法并直接在join内获取返回值。

---由于

3 个答案:

答案 0 :(得分:4)

有办法做你想做的事,但你必须要小心。这个GetBytes overload允许您指定要复制字节的字节数组,以及复制它们的索引。所以,在你的例子中,它看起来像这样:

    byte[] join = new byte[15];
    int ix = 0;
    ix = ix + Encoding.UTF8.GetBytes(first, 0, first.Length, join, ix);
    ix = ix + Encoding.UTF8.GetBytes(second, 0, second.Length, join, ix);
    string a = Encoding.UTF8.GetString(join, 0, ix);

此处的ix变量会跟踪编码的总字节数。

这里必须要小心在join数组中分配足够的字节,并且必须跟踪编码的字节数,因为UTF-8(以及许多其他编码)可能需要单个字符多个字节。

您还希望看到GetString overload,它允许您指定数组中的起始位置和字节数。

如果要编写像value1value2方法那样执行此操作的方法,则必须将字节数组和数组索引传递给方法。这些方法必须返回它们编码的字节数,否则它们必须将该值添加到索引并返回新索引。

答案 1 :(得分:3)

不是分配数组的项目,而是丢弃new byte[15]并将其分配给新数组。您可以先尝试使用List<byte>,然后将其转换为数组:

var byteList = new List<byte>(15);

byteList.AddRange(value1());
byteList.AddRange(value2());

byte[] join = byteList.ToArray();

另一种方法是为您的数组创建一个扩展方法,如下所示:

public static void SetItems<T>(this T[] source, int startIndex, IEnumerable<T> items)
{
     // I omitted the checks (index, length, null etc.) but you should add them
     int i = startIndex;

     foreach(var item in items)
          source[i++] = item;
}

然后叫它:

byte[] join = new byte[15];
join.SetItems(0, value1());
join.SetItems(4, value2());

这应该比第一个选项更快,因为它没有创建列表,但它要求您知道startIndex,在这种情况下它不应该是一个问题..

答案 2 :(得分:3)

value1value2方法返回字节数组,而您可能希望将值附加到现有的join数组。

您可以使用Array.Copy(或Buffer.BlockCopy)将返回的值放在join数组中:

var v1 = value1(); //seven byte returned. 
var v2 = value2(); //next four byte returned.
var join = new byte[v1.Length + v2.Length];

// copy v1 at index 0 of join
Array.Copy(v1, 0, join, 0, v1.Length); 
// copy v2 at index v1.Length of join
Array.Copy(v2, 0, join, v1.Length, v2.Length); 

编辑:

我做了一个小基准来测试所提方法的性能,这是结果(每种方法有6百万次重复):

Benchmark results (6000000 repetitions) :
JoinCodeUsingArrayCopy       : 4076021 ticks (1304 ms)
JoinCodeUsingSetItems        : 4873634 ticks (1559 ms)
JoinCodeUsingList            : 8729925 ticks (2793 ms)
JoinCodeUsingBufferBlockCopy : 3665075 ticks (1172 ms)

基准代码here

正如您所看到的,Array.Copy/Buffer.BlockCopy是最快的方法,即使使用列表的方法速度也不是很慢(我们谈论的是600万次迭代后差异的1.5秒)。 可能我会选择list方法,因为它是最干净的,因为它不需要直接使用偏移/起始索引。