2012-05-10 25 views
5

Tôi có bộ đệm mảng byte có kích thước tối đa là 1K. Tôi muốn viết ra một tập hợp con của mảng (bắt đầu của tập hợp con sẽ luôn là phần tử 0, nhưng độ dài mà chúng ta quan tâm là trong một biến).Làm cách nào để có được một tập con của một mảng byte (các phần tử N đầu tiên) trong C#?

Ứng dụng ở đây là nén. Tôi vượt qua trong một bộ đệm để một chức năng nén. Để đơn giản, giả sử nén sẽ dẫn đến dữ liệu bằng hoặc nhỏ hơn 1K byte.

byte[] buffer = new byte[1024]; 
while (true) 
{ 
    uncompressedData = GetNextUncompressedBlock(); 
    int compressedLength = compress(buffer, uncompressedData); 

    // Here, compressedBuffer[0..compressedLength - 1] is what we're interested in 

    // There's a method now with signature Write(byte[] compressedData) that 
    // I won't be able to change. Short of allocating a custom sized buffer, 
    // and copying data into the custom sized buffer... is there any other 
    // technique I could use to only expose the data I want? 
} 

Tôi thực sự muốn tránh một bản sao ở đây - có vẻ như hoàn toàn không cần thiết vì tất cả dữ liệu cần có trong số buffer đã có.

Trả lời

6

Nếu bạn không thể thay đổi chữ ký của phương thức thì bạn bị kẹt. Bạn không thể tạo "chế độ xem" qua mảng byte với loại byte []. Giải pháp lý tưởng cho điều đó là cho hoạt động có thể là ArraySegment<byte> hoặc byte[], sau đó là số bù và số đếm. Nếu bạn thực sự không thể thay đổi phương thức Write, thì tiếc là bạn đang mắc kẹt với việc tạo một mảng mới và sao chép dữ liệu vào nó.

+0

Ồ, bạn đã giúp tôi với WCF trước đây (với tư cách người dùng khác). Cảm ơn một lần nữa cho lời khuyên Carlos +1. – jglouie

2

Nếu chữ ký phương thức là (byte[]) bạn không thể làm gì ngoài sao chép.

Nếu bạn có thể thay đổi chữ ký:

  • suối hỗ trợ ghi trên các tập con của mảng, vì vậy nó không phải là yêu cầu bất thường để có chữ ký như Stream.Write:

    public abstract void Write( byte[] buffer, int offset, int count)

  • sự lựa chọn nào khác là để vượt qua IEnumerable<byte> để bạn có thể cắt mảng của mình theo bất kỳ cách nào bạn muốn mà không cần sao chép.

11

Bộ đệm.BlockCopy sẽ là sự lựa chọn của tôi.

Microsoft dụ: http://msdn.microsoft.com/en-us/library/system.buffer.blockcopy.aspx

const int INT_SIZE = 4; 
int[] arr = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; 
Buffer.BlockCopy(arr, 3 * INT_SIZE, arr, 0 * INT_SIZE, 4 * INT_SIZE); 
foreach (int value in arr) 
    Console.Write("{0} ", value); 
// The example displays the following output: 
//  8 10 12 14 10 12 14 16 18 20 

Mã của bạn sẽ trông như thế:

uncompressedData = GetNextUncompressedBlock();  
int compressedLength = compress(buffer, uncompressedData); 
Buffer.BlockCopy(buffer, 0, buffer, 0, compressedLength); 
3

Không có cách nào bạn có thể làm điều đó. Array.Resize thay vì thay đổi độ dài của mảng, chỉ cần sao chép nó vào một thể hiện mảng mới.

Tuy nhiên, bạn có thể sử dụng Buffer class, trong đó có hiệu suất tốt hơn:

đệm cung cấp phương pháp để sao chép byte từ một mảng của các kiểu dữ liệu khác loạt các loại nguyên thủy, có được một byte từ một mảng, thiết lập một byte trong một mảng và có được độ dài của một mảng. Lớp này cung cấp hiệu năng tốt hơn để thao tác các kiểu nguyên thủy hơn các phương thức tương tự trong lớp System.Array.

Điều này phù hợp với nhu cầu của bạn, bởi vì bạn có một mảng byte và byte là kiểu nguyên thủy.

2
byte[] b = new Byte[] {1, 2, 3, 4, 5}; 
    IEnumerable<Byte> middle = b.Skip(2).Take(3); 

Điều này sẽ cho phép bạn có được phần giữa mà bạn thích.Điều này rất có thể tạo ra một bản sao, nhưng tôi không nghĩ rằng bạn nên cố gắng tránh điều đó.

Các vấn đề liên quan