2008-08-21 70 views
26

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

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

回答

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(); 
    } 
} 
0

你不能。你可能想要的是保持一个起点和数量的项目;本质上来说,构建迭代器。如果这是C++,则可以使用std::vector<int>并使用内置的。在C#中,我会构建一个小的迭代器类,它包含开始索引,计数并实现IEnumerable<>

1

我不知道你的意思是:

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

在大多数语言中,肯定是C#,一旦数组被分配,就没有办法改变它的大小。这听起来像你正在寻找一种方法来改变数组的长度,你不能。你也想以某种方式回收数组第二部分的内存,以创建第二个数组,这也是你无法做到的。

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

17

仅供参考。 System.ArraySegment<T>结构基本上与上面的代码中的ArrayView<T>是一样的。如果你愿意,你可以用相同的方式使用这个开箱即用的结构。

+0

有趣。太糟糕了,我在做这个项目时没有看到这个。无论如何感谢您的信息。 – 2009-11-02 17:23:10

13

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

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

;)

+3

该OP想知道如何做到这一点**,而不必创建一个新的字节数组,并一次复制每个字节**但这正是你的LINQ代码所做的。两次。 – 2011-12-21 22:00:56

+0

..这帮助我解决了一个我没有通过`ArraySegment `得到的问题.. .. – AceMark 2012-03-18 15:19:46

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; 
     } 
    } 
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); 
    } 
}