Преобразовать байтовый массив в сегменты массива определенной длины - PullRequest
0 голосов
/ 08 сентября 2018

У меня есть байтовый массив, и я хотел бы вернуть последовательные фрагменты (в виде новых байтовых массивов) определенного размера.

Я пытался:

originalArray = BYTE_ARRAY
var segment = new ArraySegment<byte>(originalArray,0,640); 
byte[] newArray = new byte[640];
for (int i = segment.Offset; i <= segment.Count; i++)
{
newArray[i] = segment.Array[i];
}

Очевидно, что это только создает массив первых 640 байтов из исходного массива. В конечном счете, я хочу цикл, который проходит через первые 640 байтов и возвращает массив этих байтов, затем проходит через следующие 640 байтов и возвращает массив из тех байтов. Целью этого является отправка сообщений на сервер, и каждое сообщение должно содержать 640 байтов. Я не могу гарантировать, что исходная длина массива делится на 640.

Спасибо

Ответы [ 3 ]

0 голосов
/ 08 сентября 2018

если скорость не имеет значения

var bytes = new byte[640 * 6];

for (var i = 0; i <= bytes.Length; i+=640)
{
   var chunk = bytes.Skip(i).Take(640).ToArray();
   ...
}

В качестве альтернативы вы можете использовать

Span

Span<byte> bytes = arr; // Implicit cast from T[] to Span<T>

...

slicedBytes = bytes.Slice(i, 640);

BlockCopy

Обратите внимание, что это, вероятно, будет самым быстрым из 3

var chunk = new byte[640]
Buffer.BlockCopy(bytes, i, chunk, 0, 640);
0 голосов
/ 08 сентября 2018

Вы можете написать общий вспомогательный метод, например так:

public static IEnumerable<T[]> AsBatches<T>(T[] input, int n)
{
    for (int i = 0, r = input.Length; r >= n; r -= n, i += n)
    {
        var result = new T[n];
        Array.Copy(input, i, result, 0, n);
        yield return result;
    }
}

Затем вы можете использовать его в цикле foreach:

byte[] byteArray = new byte[123456];

foreach (var batch in AsBatches(byteArray, 640))
{
    Console.WriteLine(batch.Length); // Do something with the batch.
}

Или, если вы хотите список партий, просто сделайте это:

List<byte[]> listOfBatches = AsBatches(byteArray, 640).ToList();

Если вы хотите получить фантазию, вы можете сделать это методом расширения, но это рекомендуется только в том случае, если вы будете часто его использовать (не создавайте метод расширения для того, что вы будете вызывать только в одном месте! ).

Здесь я изменил имя на InChunksOf(), чтобы сделать его более читабельным:

public static class ArrayExt
{
    public static IEnumerable<T[]> InChunksOf<T>(this T[] input, int n)
    {
        for (int i = 0, r = input.Length; r >= n; r -= n, i += n)
        {
            var result = new T[n];
            Array.Copy(input, i, result, 0, n);
            yield return result;
        }
    }
}

Который вы могли бы использовать так:

byte[] byteArray = new byte[123456];

// ... initialise byteArray[], then:

var listOfChunks = byteArray.InChunksOf(640).ToList();

[EDIT] Исправленный терминатор контура от r > n до r >= n.

0 голосов
/ 08 сентября 2018

Если вы действительно хотите создать новых массивов из каждого 640-байтового блока, то вы ищете .Skip и .Take

Вот рабочий пример (и ответ из примера ), который я взломал вместе.

using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;

class MainClass {
public static void Main (string[] args) {
        // mock up a byte array from something
        var seedString = String.Join("", Enumerable.Range(0, 1024).Select(x => x.ToString()));
        var byteArrayInput = Encoding.ASCII.GetBytes(seedString);

        var skip = 0;
        var take = 640;
        var total = byteArrayInput.Length;

        var output = new List<byte[]>();

        while (skip + take < total) {
            output.Add(byteArrayInput.Skip(skip).Take(take).ToArray());
            skip += take;
        }

        output.ForEach(c => Console.WriteLine($"chunk: {BitConverter.ToString(c)}"));
    }
}

Вероятно, действительно лучше использовать ArraySegment правильно - если только это не задание для изучения расширений LINQ.

...