【问题标题】:Convert byte array to array segments of a certain length将字节数组转换为一定长度的数组段
【发布时间】:2019-02-13 09:14:25
【问题描述】:

我有一个字节数组,我想返回一定大小的顺序块(以新字节数组的形式)。

我试过了:

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 个字节并返回一个 THOSE 字节数组。这样做的目的是向服务器发送消息,每条消息必须包含 640 个字节。我不能保证原始数组长度可以被 640 整除。

谢谢

【问题讨论】:

  • 首先,请注意:ArraySegment 仍在使用与原始数组相同的缓冲区。这通常正是您可能想要的,但这不是您在其余问题中所描述的。
  • 是的,要正确回答这个问题,我们需要知道 (a) 您是否需要制作原始数据的实际副本,还是分块引用原始数据就足够了? (b) 你可以用 IEnumerable 来处理块,还是必须是一个数组? (c) 您使用的是什么版本的 C# 和 .Net?这些问题的答案将决定最高效的解决方案。
  • a) 需要是一个副本 b) 它需要是一个字节数组 c) 它和 asp.net core mcc 应用程序
  • 如果缓冲区不是 640 的倍数,那么剩余字节会怎样?它们只是被忽略了,还是用零填充到 640 个字节并发送,或者其他什么?
  • 我假设它只是被忽略了。我正在尝试根据此文档“developer.nexmo.com/voice/voice-api/guides/websockets”将音频写入 websocket,这需要 640 字节的消息大小

标签: c# arrays loops split byte


【解决方案1】:

如果速度不是问题

var bytes = new byte[640 * 6];

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

你也可以使用

跨度

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

...

slicedBytes = bytes.Slice(i, 640);

块复制

请注意,这可能是 3 个中最快的

var chunk = new byte[640]
Buffer.BlockCopy(bytes, i, chunk, 0, 640);

【讨论】:

    【解决方案2】:

    如果您真的想从每个 640 字节的块中创建 新数组,那么您正在寻找 .Skip.Take

    这是我一起破解的一个工作示例(和一个repl of the example)。

    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 扩展的作业。

    【讨论】:

      【解决方案3】:

      你可以像这样写一个通用的辅助方法:

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

      [编辑] 将循环终止符从 r &gt; n 更正为 r &gt;= n

      【讨论】:

      • 如果原始字节数组的长度不能被 640 整除,这将如何处理原始字节数组的剩余部分?我只是想忽略不等于 640 字节的最终“批次”。
      • @HarryStuart 这正是它的作用——任何剩余的字节都将被忽略。
      • 太棒了,我将在今晚晚些时候或明天早上测试代码
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-07
      • 2019-12-10
      • 1970-01-01
      • 2013-03-10
      • 1970-01-01
      相关资源
      最近更新 更多