【问题标题】:c# efficient way of reading arrays of specific type from streamc#从流中读取特定类型数组的有效方法
【发布时间】:2018-03-03 18:51:46
【问题描述】:

我正在寻找一种从流中读取特定类型的多个数组的有效方法。

到目前为止,我正在使用下面这样的类来读取单个值,例如:int, byte, sbyte, uint, short, ushort, ... 但也适用于数组,例如:ushort[]、short[]、uint[]、int[]、byte[]、sbyte[]、...

    public byte[] ReadBytes(int count)
    {
      byte[] buffer = new byte[count];
      int retValue = _Stream.Read(buffer, 0, count);
      return buffer;
    }

    public ushort ReadUshort()
    {
      byte[] b = ReadBytes(2);
      if (BitConverter.IsLittleEndian) // for motorola (big endian)
        Array.Reverse(b);
      return BitConverter.ToUInt16(b, 0);
    }

    public ushort[] ReadUshorts(int count) 
    {
       ushort[] data = new ushorts[count];
       for (int i = 0; i < count; i++)
       {
          data[i] = ReadUshort();
       }
       return data;
    }

   public uint ReadUint() 
   {
       byte[] b = ReadBytes(4);
      if (BitConverter.IsLittleEndian) // for motorola (big endian)
        Array.Reverse(b);
      return BitConverter.ToUInt32(b, 0);
   }

   public uint[] ReadUints(int count)
   {
      // ...
   }

与我在这里共享的代码 sn-p 相比,有没有更有效的方法来读取数组?

我有一种感觉,for-loop 和每次读取调用的组合并不是那么有效。但问题是我每次都需要检查 IsLittleEndian 并在需要时反转,所以我可以读取多个字节。不确定这是否可以更有效地重写。

【问题讨论】:

  • 可以随时优化,比如ReadUshorts实现了ReadUshort的逻辑,可以一次性读取所有数据。但是你会失去维护。它对您的用例至关重要吗?
  • 好吧,我宁愿写一些更难但更快的代码。

标签: c# arrays


【解决方案1】:

您可以编写一个泛型方法,并使用Buffer.BlockCopy 将数据复制到目标数组中:

    public static T[] ReadElements<T>(Stream input, int count)
    {
        int bytesPerElement = Marshal.SizeOf(typeof(T));
        byte[] buffer = new byte[bytesPerElement * count];

        int remaining = buffer.Length;
        int offset = 0;
        while (remaining > 0)
        {
            int read = input.Read(buffer, offset, remaining);
            if (read == 0) throw new EndOfStreamException();
            offset += read;
            remaining -= read;
        }

        if (BitConverter.IsLittleEndian)
        {
            for (int i = 0; i < buffer.Length; i += bytesPerElement)
            {
                Array.Reverse(buffer, i, bytesPerElement);
            }
        }

        T[] result = new T[count];
        Buffer.BlockCopy(buffer, 0, result, 0, buffer.Length);
        return result;
    }

【讨论】:

  • 这看起来像是一个干净的方法,我只是想知道是否有一种方法可以直接读取 bigendian/littleendian 而不是为 array.reverse 提供额外的 for 循环?
  • 我也想知道这一点,但最终 something 将不得不遍历字节来交换它们。 Array.Reverse 不是最快的解决方案,但是可以通过这种方式处理泛型类型的不同数据大小。
猜你喜欢
  • 2011-11-24
  • 2017-01-13
  • 2018-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 1970-01-01
相关资源
最近更新 更多