Resolved read bytes from middle of file?

zunebuggy65

Active member
Joined
Oct 12, 2023
Messages
42
Programming Experience
3-5
I have a binary file that contains old style bytes (values of 0 - 255 and no Words). I have a need to read the file, at times, from the middle (x number of bytes into the file by n number of bytes in length).

All examples I find online you have to read each byte sequentially until you get to your starting byte (x) and then count (n) number of bytes from there. This seems slow.

Do I need a third party tool to do this in VB.net?

If not, can you please point me to an example of reading this file from the xth byte and nth bytes in length?

Thank you.
 
FileStream class will let you do that. Use the Position property or Seek method to set where to start reading, then Read or ReadAsync method to read the bytes.
 
I do not fully understand the FileStream class. If I were to use the following code:

VB.NET:
Using myFile As New FileStream(myPath, FileMode.Open, FileAccess.Read)
    Try

        Dim myChunk = 999
        Dim myFileLen As Integer = CInt(myFile.Length)
        Dim myBuff(myFileLen) as Byte
        Dim myBlock(myChunk) as Byte
        Dim myCount As Integer = -1
        Dim myPos As Integer = 256

        While myCount <> 0
            myCount = myFile.Read(myBlock, 0, myChunk-1)
            Array.Copy(myBlock, 0, myBuff, myPos, myCount)
            myPos = myPos + myCount
        End While

        For Each myElement As Integer In myBuff
            Console.WriteLine(myElement)
        Next

    End Try
End Using

could you explain this to me? If I understand it, in the example above, myPos is the starting point in the file and myChunk is the length?

Do you have to copy it to an array?

Do all binary files end with -1?
 
That code reads a block of data from the file into one array, then copies the contents of that array into another array. Each iteration of the loop, it advances the position from which to read and the position to which to copy by the length of a block. What you should be doing is reading the documentation for each of types/members you don't understand and running the code in the debugger and watching the relevant variables and other expressions as you step through it.
 
I have been reading the documentation from Microsoft on the .Read() and .Seek() functions but they are very vague on what each parameter is and how to use them. Also, all the examples I can find are in C, which I am not strong at. I can view the C code and tell somewhat what is going on, but not exactly.

I have been programming in VB6 for years but fairly new to VB.net and very new to FileStream.

I have a 35MB .bin file that I do not want to load the entire file into an array. I will if I have to. I have that working, but if someone has low memory, they are going to definitely get a warning.

The 35MB file I'm reading is made up of Bytes (0 -255).

I would just like to start at the beginning of the file and load say 256, 512 or 1024 Bytes into the array and work with that. When I am done with that, load the next 256 Bytes or so, etc. to the End of File.

I have found a few examples online but none explain the fs.Read(x, 0, n-1) statement. In this example, what is 'x' and what is 'n'? I suspect x is the starting Byte and n is the 256, 512 or 1024 array size?

If so, how do I handle reading this when I reach the End of File? I saw something about fs.Seek(a, b) but no examples in VB.net explaining what a and b are in this command or how to use this command.

In the example above for .Read(), all examples online contain 0 as the second parameter but I'm not sure what this parameter is? If it's the starting location of the chunk then I should make this a variable not a constant?

In VB6 and VBA I have read binary files with the Get statement, but not huge files, so I never dealt with reading files from the middle of the file in chunks and I guess that's what I need to do now, but I need to understand all the parameters in the .Read() and .Seek() commands.

Thank you.
 
Example reading 4 bytes into an array from position 123456:
VB.NET:
Using stream = File.OpenRead("path")
    stream.Position = 123456
    'same as above: stream.Seek(123456, SeekOrigin.Begin)
    Dim bytes(3) As Byte
    stream.Read(bytes, 0, 4)
End Using
Read offset parameter:
The byte offset in array at which the read bytes will be placed.
 
Thank you JohnH. That did help.

I created this small test project just to play with the FileStream a bit, but I am getting results that I do not understand.

VB.NET:
Imports System.IO
Public Class Form1
    Private Sub btnWrite_Click(sender As Object, e As EventArgs) Handles btnWrite.Click
        Dim binWrite As BinaryWriter
        Dim myByte As Byte
        Dim myPath As String
        myPath = "C:\Users\luger\source\repos\FileStreamTest\bin\Debug\"
        binWrite = New BinaryWriter(File.Open(myPath & "testme.bin", FileMode.Create))
        Using binWrite
            For myByte = 0 To 128
                binWrite.Write(myByte)
            Next myByte
        End Using
        binWrite.Close()
        For myByte = 0 To 128
            TextBox1.Text = TextBox1.Text & Format(myByte, "000") & " "
        Next myByte
    End Sub

    Private Sub btnRead_Click(sender As Object, e As EventArgs) Handles btnRead.Click
        Dim myPath As String
        myPath = "C:\Users\luger\source\repos\FileStreamTest\bin\Debug\"
        Dim bytesRead As Integer
        Dim buffer(32) As Byte
        Using inFile As New IO.FileStream(myPath & "testme.bin", FileMode.Open)
            Do
                bytesRead = inFile.Read(buffer, 0, buffer.Length)
                If bytesRead > 0 Then
                    TextBox2.Text = TextBox2.Text & Format(bytesRead, "000") & " "
                End If
                TextBox2.Text = TextBox2.Text & Format(bytesRead, "000") & " "
            Loop While bytesRead > 0
        End Using
    End Sub
End Class

I have a form, two Multiline TextBoxes, two Buttons (Write and Read). When I Click the Write button, it creates a simple binary file and fills it with Bytes 0 through 128.

When I click the Read button, the second TextBox fills with '033 033 033 033 033 033 030 030 000'. I was expecting 000 001 002 ... 031 since my Buffer is 32 and I guess I am starting from the 0 Byte.

If I can get this working, I'd like to be able to (for example) start at Byte 32 and read the next 32 Bytes so that TextBox2 fills up with 032, 033, 034 ... 063.

The fact that it displays '033 033 033 033 033 033 030 030 000' makes no sense at all.
 
The return value of Read method is the number of bytes read (into array). Your buffer.Length = 33 and that is number you request to be read.

Returns​

Int32
The total number of bytes read into the buffer. This might be less than the number of bytes requested if that number of bytes are not currently available, or zero if the end of the stream is reached.
 
Oh I see. I thought Read read the Bytes but it just controls then length. I'm assuming .Seek will help me get the Bytes I was expecting?

Thank you again.
 
I am getting so close now. Here is the code I am playing with.

VB.NET:
Imports System.IO
Public Class Form1
    Private Sub btnWrite_Click(sender As Object, e As EventArgs) Handles btnWrite.Click
        Dim binWrite As BinaryWriter
        Dim myByte As Byte
        Dim myPath As String
        myPath = "C:\Users\luger\source\repos\FileStreamTest\bin\Debug\"
        binWrite = New BinaryWriter(File.Open(myPath & "testme.bin", FileMode.Create))
        Using binWrite
            For myByte = 0 To 128
                binWrite.Write(myByte)
            Next myByte
        End Using
        binWrite.Close()
        For myByte = 0 To 128
            TextBox1.Text = TextBox1.Text & Format(myByte, "000") & " "
        Next myByte
    End Sub

    Private Sub btnRead_Click(sender As Object, e As EventArgs) Handles btnRead.Click
        Dim stPos As Integer
        Dim bytLen As Integer
        Dim buffer As Byte
        Dim myPath As String
        readX(myPath & "testme.bin", 10, 32)
        For t = 1 To 32
            TextBox2.Text = TextBox2.Text & Format(buffer(t), "000") & " "
        Next t
    End Sub

    Function readX(ByVal file As String, ByVal offset As UInt64, ByVal count As UInt64) As Byte()
        Dim buffer() As Byte = New Byte(count - 1) {}
        Using fs As New FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)
            fs.Seek(offset, SeekOrigin.Begin)
            'MsgBox(SeekOrigin.Begin)
            fs.Read(buffer, 0, count)
            'MsgBox(buffer(0))
        End Using
        Return buffer
    End Function
End Class

But it returns the error: Structure 'Byte' cannot be indexed because it has no default property. Even Googling this error does not produce any good explanations AND if I add (inside my Function) MsgBox(buffer(0)) or MsgBox(buffer(3)), etc. It displays the expected value so I am not sure why in the btnRead_Click event, the buffer(t) causes an error.

Thank you.
 
Oh I see. I thought Read read the Bytes but it just controls then length. I'm assuming .Seek will help me get the Bytes I was expecting?

Thank you again.

You should stop assuming and start reading the documentation, which tells you what these methods do. Of course Read will read the data. As the documentation clearly states, you provide the array to read the data into, tell it where in that array to start writing the data and the number of bytes you want to read. It will read up to that many bytes into the provided array at the specified position and then return the number of bytes actually read. For example, if you want to read 100 bytes but there are only 50 left in the stream, it will return 50 rather than 100. Seek simply moves the file pointer to a specific location in the stream so that the next read or write operation will read or write bytes at that position.

This is all in the documentation that you should already have read. A link to that documentation was provided two days ago.
 
As for your error, it's because you have declared buffer as type Byte instead of type Byte(), i.e. as a byte array. Your code doesn't really make sense as it is. You declare a buffer variable in the first method as type Byte and then try to use that latter without having assigned anything to it. Your readX method returns a Byte array but, when you call that method, you don't assign the return value anywhere so it's lost.

If you can't implement the basics of declaring and assigning variables and calling functions, anything more advanced will never work and you'll have trouble working out where the issue actually is, exactly as is happening. I would suggest that you forget FileStreams for the moment and go back to basics. Learn how to do things like declare and set variables and call functions first, before you try to use those things to do something more advanced.

In this specific case, you need to declare your variable as the correct type and then assign the return value of your method to it:
VB.NET:
Dim buffer As Byte()
Dim myPath As String

buffer = readX(myPath & "testme.bin", 10, 32)
Better still, just assign the variable where you use it:
VB.NET:
Dim myPath As String

Dim buffer As Byte() = readX(myPath & "testme.bin", 10, 32)
It should be pretty obvious that that will still not work though, because you declare the myPath variable and then immediately use it without assigning a value to it.
 
You started out asking how to seek into the middle of the file and read N bytes.. And now youre asking how to sequentially read blocks of N starting from the beginning

Which is it?
 
Back
Top