juFo
juFo

Reputation: 18567

c# efficient way of reading arrays of specific type from stream

I'm looking for an efficient way of reading multiple arrays of a specific type from a stream.

So far I'm using a class like this below to read single values like: int, byte, sbyte, uint, short, ushort, ... but also for arrays like: 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)
   {
      // ...
   }

Is there a more efficient way compared to code snippet I've shared here to read the arrays?

I have a feeling that a combination of for-loop and each time a single read call is not so efficient. But the problem is that I need to check for IsLittleEndian each time and reverse if needed, so I can read many bytes at ones. Not sure if this could be rewritten more efficiently.

Upvotes: 0

Views: 258

Answers (1)

C.Evenhuis
C.Evenhuis

Reputation: 26436

You could write a generic method, and use Buffer.BlockCopy to copy the data into the target array:

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

Upvotes: 2

Related Questions