locked
How to read a few parts from a byte array and not the entire array RRS feed

  • Question

  • I am trying to read different parts of a byte array and not the entire array. How would I do this? I would also like to format an array when creating one. An example would be the first few parts a string then some integers. Thanks
    Thursday, May 5, 2011 9:48 PM

Answers

  • The methods of the BitConverter class all accept a byte array and an integer from which to start reading.

    The GetString method of Encoding also accepts an array and an index to start reading from.

    Let's say you have recieved a blob of data from some device laid out like this:

    Message Length (Integer - Integers are 32 bits, so they use 4 bytes)
    Message (String - Each character of an ANSI string uses 1 byte)
    Padding (some 0s - Often values are aligned to a 4 byte boundary, so there are padding bytes here so that the next field starts at byte 20)
    Value (Double - a 64 bit value so it uses 8 bytes)

    Here's a sample:

    00 0D Message Length
    01 00 Message Length
    02 00 Message Length
    03 00 Message Length
    04 48 H
    05 65 e
    06 6C l
    07 6C l
    08 6F o
    09 20 " "
    10 57 W
    11 6F o
    12 72 r
    13 6C l
    14 64 d
    15 0D Cr
    16 0A Lf
    17 00 Padding
    18 00 Padding
    19 00 Padding
    20 C9 Value
    21 76 Value
    22 BE Value
    23 9F Value
    24 0C Value
    25 24 Value
    26 FE Value
    27 40 Value

    You can use the classes mentioned like this to read the values out:

     

    ' The message length field starts at index 0:
    Dim messageLength As String = BitConverter.ToInt32(bytes, 0)
    ' The message itself starts at index 4:
    Dim message As String = System.Text.ASCIIEncoding.ASCII.GetString(bytes, 4, messageLength)
    ' The double value starts at index 20:
    Dim value As Double = BitConverter.ToDouble(bytes, 20)
    ' Write the information out to the user:
    Console.WriteLine("Message length: " & messageLength)
    Console.WriteLine("Message: " & message)
    Console.WriteLine("Value: " & value)
    Friday, May 6, 2011 6:55 PM
  • I am trying to read different parts of a byte array and not the entire array. How would I do this? I would also like to format an array when creating one. An example would be the first few parts a string then some integers. Thanks
    Another option is Buffer.BlockCopy which allows you to copy the bytes from one array of one type to another array of another type.

    Stephen J Whiteley
    Friday, May 6, 2011 1:40 PM
  • You say you want to format an array when creating one - I guess that means working in the other direction. If you are always writing out the same set of values to the array then it might be simplest to define a Structure to hold the data. You can then pin the structure in memory, and directly copy the memory into a byte array. If the strings are variable lengths then it probably makes this too tricky.

    Otherwise you just have to do it manually. Declare an array large enough to hold the bytes, then use BitConverter and the Encoding class to convert each string and numeric value into a byte array, and write them into the larger array (here's where Buffer.BlockCopy or Array.CopyTo are used).

    Module Module1

        
    Sub Main()
            
    Dim bytes = MakeByteArray()
            
    ' The message length field starts at index 0:
            
    Dim messageLength As String = BitConverter.ToInt32(bytes, 0)
            
    ' The message itself starts at index 4:
            
    Dim message As String = System.Text.ASCIIEncoding.ASCII.GetString(bytes, 4, messageLength)
            
    ' The double value starts at index 20:
            
    Dim value As Double = BitConverter.ToDouble(bytes, 20)
            
    ' Write the information out to the user:
            
    Console.WriteLine("Message length: " & messageLength)
            
    Console.WriteLine("Message: " & message)
            
    Console.WriteLine("Value: " & value)
        
    End Sub

        
    Private Function MakeByteArray() As Byte()
            
    Dim message As String = "Hello World" & vbCrLf
            
    Dim bytes(27) As Byte
            
    ' Read the message length  - it's an integer.
            
    ' Get the bytes of the integer into an array with GetBytes.
            
    ' Copy the bytes of the integer into our target array, called bytes.
            
    Buffer.BlockCopy(BitConverter.GetBytes(message.Length), 0, bytes, 0, 4)
            
    ' Similar for the message itself, but we don't need to do the copy as GetBytes can read the
            
    '  string into our array.
            System.Text.
    ASCIIEncoding.ASCII.GetBytes(message, 0, message.Length, bytes, 4)
            
    ' We don't need to do the padding, the default value of Byte is 0, so the array has 0s at
            
    ' those indices.
            
    Dim val As Double = 123456.789
            
    ' Copy the 8 bytes of val into the array called bytes writing into it at index 20 onwards.
            
    Buffer.BlockCopy(BitConverter.GetBytes(val), 0, bytes, 20, 8)
            
    Return bytes.ToArray
        
    End Function

    End Module



    Friday, May 6, 2011 7:58 PM

All replies

  • Bitconverter will get the numeric types.

    System.Text.Encoding.ASCII gets you an Encoding object that you can read to use an ASCII string from bytes, you can use the GetString method.

    Thursday, May 5, 2011 9:58 PM
  • How do i get the first few parts of the array and not the entire array?
    Friday, May 6, 2011 12:52 PM
  • Array.CopyTo

    Creates for you a deep copy from every part you want.

    http://msdn.microsoft.com/en-us/library/system.array.copyto(v=VS.100).aspx


    Success
    Cor
    Friday, May 6, 2011 12:59 PM
  • I am trying to read different parts of a byte array and not the entire array. How would I do this? I would also like to format an array when creating one. An example would be the first few parts a string then some integers. Thanks
    Another option is Buffer.BlockCopy which allows you to copy the bytes from one array of one type to another array of another type.

    Stephen J Whiteley
    Friday, May 6, 2011 1:40 PM
  • Stephen, 

    That was the one I was looking for, it is a little bit faster.

    :-)

     


    Success
    Cor
    Friday, May 6, 2011 2:02 PM
  • The methods of the BitConverter class all accept a byte array and an integer from which to start reading.

    The GetString method of Encoding also accepts an array and an index to start reading from.

    Let's say you have recieved a blob of data from some device laid out like this:

    Message Length (Integer - Integers are 32 bits, so they use 4 bytes)
    Message (String - Each character of an ANSI string uses 1 byte)
    Padding (some 0s - Often values are aligned to a 4 byte boundary, so there are padding bytes here so that the next field starts at byte 20)
    Value (Double - a 64 bit value so it uses 8 bytes)

    Here's a sample:

    00 0D Message Length
    01 00 Message Length
    02 00 Message Length
    03 00 Message Length
    04 48 H
    05 65 e
    06 6C l
    07 6C l
    08 6F o
    09 20 " "
    10 57 W
    11 6F o
    12 72 r
    13 6C l
    14 64 d
    15 0D Cr
    16 0A Lf
    17 00 Padding
    18 00 Padding
    19 00 Padding
    20 C9 Value
    21 76 Value
    22 BE Value
    23 9F Value
    24 0C Value
    25 24 Value
    26 FE Value
    27 40 Value

    You can use the classes mentioned like this to read the values out:

     

    ' The message length field starts at index 0:
    Dim messageLength As String = BitConverter.ToInt32(bytes, 0)
    ' The message itself starts at index 4:
    Dim message As String = System.Text.ASCIIEncoding.ASCII.GetString(bytes, 4, messageLength)
    ' The double value starts at index 20:
    Dim value As Double = BitConverter.ToDouble(bytes, 20)
    ' Write the information out to the user:
    Console.WriteLine("Message length: " & messageLength)
    Console.WriteLine("Message: " & message)
    Console.WriteLine("Value: " & value)
    Friday, May 6, 2011 6:55 PM
  • You say you want to format an array when creating one - I guess that means working in the other direction. If you are always writing out the same set of values to the array then it might be simplest to define a Structure to hold the data. You can then pin the structure in memory, and directly copy the memory into a byte array. If the strings are variable lengths then it probably makes this too tricky.

    Otherwise you just have to do it manually. Declare an array large enough to hold the bytes, then use BitConverter and the Encoding class to convert each string and numeric value into a byte array, and write them into the larger array (here's where Buffer.BlockCopy or Array.CopyTo are used).

    Module Module1

        
    Sub Main()
            
    Dim bytes = MakeByteArray()
            
    ' The message length field starts at index 0:
            
    Dim messageLength As String = BitConverter.ToInt32(bytes, 0)
            
    ' The message itself starts at index 4:
            
    Dim message As String = System.Text.ASCIIEncoding.ASCII.GetString(bytes, 4, messageLength)
            
    ' The double value starts at index 20:
            
    Dim value As Double = BitConverter.ToDouble(bytes, 20)
            
    ' Write the information out to the user:
            
    Console.WriteLine("Message length: " & messageLength)
            
    Console.WriteLine("Message: " & message)
            
    Console.WriteLine("Value: " & value)
        
    End Sub

        
    Private Function MakeByteArray() As Byte()
            
    Dim message As String = "Hello World" & vbCrLf
            
    Dim bytes(27) As Byte
            
    ' Read the message length  - it's an integer.
            
    ' Get the bytes of the integer into an array with GetBytes.
            
    ' Copy the bytes of the integer into our target array, called bytes.
            
    Buffer.BlockCopy(BitConverter.GetBytes(message.Length), 0, bytes, 0, 4)
            
    ' Similar for the message itself, but we don't need to do the copy as GetBytes can read the
            
    '  string into our array.
            System.Text.
    ASCIIEncoding.ASCII.GetBytes(message, 0, message.Length, bytes, 4)
            
    ' We don't need to do the padding, the default value of Byte is 0, so the array has 0s at
            
    ' those indices.
            
    Dim val As Double = 123456.789
            
    ' Copy the 8 bytes of val into the array called bytes writing into it at index 20 onwards.
            
    Buffer.BlockCopy(BitConverter.GetBytes(val), 0, bytes, 20, 8)
            
    Return bytes.ToArray
        
    End Function

    End Module



    Friday, May 6, 2011 7:58 PM