如何拆分字节数组

时间:2008-08-21 19:01:28

标签: c# arrays split

我在内存中有一个字节数组,从文件中读取。我想在某个点(索引)拆分字节数组,而不必只创建一个新的字节数组并一次复制每个字节,从而增加了操作的内存占用量。我想要的是这样的:

byte[] largeBytes = [1,2,3,4,5,6,7,8,9];  
byte[] smallPortion;  
smallPortion = split(largeBytes, 3);  

smallPortion等于1,2,3,4
largeBytes等于5,6,7,8,9

8 个答案:

答案 0 :(得分:20)

FYI。 System.ArraySegment<T>结构与上面代码中的ArrayView<T>基本相同。如果您愿意,可以以相同的方式使用这种开箱即用的结构。

答案 1 :(得分:18)

在使用Linq的C#中,你可以这样做:

smallPortion = largeBytes.Take(4).ToArray();
largeBytes = largeBytes.Skip(4).Take(5).ToArray();

答案 2 :(得分:14)

我就是这样做的:

using System;
using System.Collections;
using System.Collections.Generic;

class ArrayView<T> : IEnumerable<T>
{
    private readonly T[] array;
    private readonly int offset, count;

    public ArrayView(T[] array, int offset, int count)
    {
        this.array = array;
        this.offset = offset;
        this.count = count;
    }

    public int Length
    {
        get { return count; }
    }

    public T this[int index]
    {
        get
        {
            if (index < 0 || index >= this.count)
                throw new IndexOutOfRangeException();
            else
                return this.array[offset + index];
        }
        set
        {
            if (index < 0 || index >= this.count)
                throw new IndexOutOfRangeException();
            else
                this.array[offset + index] = value;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = offset; i < offset + count; i++)
            yield return array[i];
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        IEnumerator<T> enumerator = this.GetEnumerator();
        while (enumerator.MoveNext())
        {
            yield return enumerator.Current;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        byte[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
        ArrayView<byte> p1 = new ArrayView<byte>(arr, 0, 5);
        ArrayView<byte> p2 = new ArrayView<byte>(arr, 5, 5);
        Console.WriteLine("First array:");
        foreach (byte b in p1)
        {
            Console.Write(b);
        }
        Console.Write("\n");
        Console.WriteLine("Second array:");
        foreach (byte b in p2)
        {
            Console.Write(b);
        }
        Console.ReadKey();
    }
}

答案 3 :(得分:3)

试试这个:

private IEnumerable<byte[]> ArraySplit(byte[] bArray, int intBufforLengt)
    {
        int bArrayLenght = bArray.Length;
        byte[] bReturn = null;

        int i = 0;
        for (; bArrayLenght > (i + 1) * intBufforLengt; i++)
        {
            bReturn = new byte[intBufforLengt];
            Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt);
            yield return bReturn;
        }

        int intBufforLeft = bArrayLenght - i * intBufforLengt;
        if (intBufforLeft > 0)
        {
            bReturn = new byte[intBufforLeft];
            Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft);
            yield return bReturn;
        }
    }

答案 4 :(得分:1)

我不确定你的意思:

  

我想将字节数组拆分到某个点(索引),而不必一次创建一个新的字节数组并复制每个字节,从而增加了操作的内存占用量。

在大多数语言中,当然C#,一旦分配了数组,就无法改变它的大小。听起来你正在寻找一种方法来改变阵列的长度,你不能这样做。你还想以某种方式回收数组第二部分的内存,创建第二个数组,你也做不到。

总结:只需创建一个新数组。

答案 5 :(得分:0)

你做不到。你可能想要的是保持一个起点和数量的项目;实质上,构建迭代器。如果这是C ++,您可以使用std::vector<int>并使用内置的。

在C#中,我将构建一个小的迭代器类,它包含起始索引,计数和实现IEnumerable<>

答案 6 :(得分:0)

作为Eren said,您可以使用ArraySegment<T>。这是一个扩展方法和用法示例:

public static class ArrayExtensionMethods
{
    public static ArraySegment<T> GetSegment<T>(this T[] arr, int offset, int? count = null)
    {
        if (count == null) { count = arr.Length - offset; }
        return new ArraySegment<T>(arr, offset, count.Value);
    }
}

void Main()
{
    byte[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    var p1 = arr.GetSegment(0, 5);
    var p2 = arr.GetSegment(5);
    Console.WriteLine("First array:");
    foreach (byte b in p1)
    {
        Console.Write(b);
    }
    Console.Write("\n");
    Console.WriteLine("Second array:");
    foreach (byte b in p2)
    {
        Console.Write(b);
    }
}

答案 7 :(得分:0)

我尝试了不同的算法:

  • Skip().Take() => 迄今为止最糟糕的
  • 数组.复制
  • ArraySegment
  • new Guid(int, int16, int16 ...)

我现在使用这种扩展方法的最新是最快的:

        public static Guid ToGuid(this byte[] byteArray, int offset)
        {
            return new Guid(BitConverter.ToInt32(byteArray, offset), BitConverter.ToInt16(byteArray, offset + 4), BitConverter.ToInt16(byteArray, offset + 6), byteArray[offset + 8], byteArray[offset + 9], byteArray[offset + 10], byteArray[offset + 11], byteArray[offset + 12], byteArray[offset + 13], byteArray[offset + 14], byteArray[offset + 15]);
        }

具有 10000000 个 guid 的字节数组:

Done (Skip().Take()) in 1,156ms (for only 100000 guids :))
Done (Array.Copy) in 1,219ms
Done (ToGuid extension) in 994ms
Done (ArraySegment) in 2,411ms