Reputation: 4056
I am attempting to read a random access file, but I am getting the following error on the first file Error 5 (unable to read beyond end of the stream)
. I am not sure what I am doing wrong here, how might I fix this issue?
Structure StdSections
'UPGRADE_WARNING: Fixed-length string size must fit in the buffer. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="3C1E4426-0B80-443E-B943-0627CD55D48B"'
<VBFixedString(15), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=15)> Public A() As Char 'BEAM --- complete beam designation 15
'UPGRADE_WARNING: Fixed-length string size must fit in the buffer. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="3C1E4426-0B80-443E-B943-0627CD55D48B"'
<VBFixedString(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> Public B() As Char 'DSG --- shape ie "W" or "C" 2
Dim C As Single 'DN --- nominal depth of section 4
Dim d As Single 'WGT --- weight 4
.
.
.
End structure
''Note 'File1'is the existing RAF and holds complete path!
Dim i,ffr,fLength,lastmembNo as integer
sectionFound = False
Dim std As new StdSections
fLength = Len(std)
If fLength = 0 Then fLength = 168 ' 177
ffr = FreeFile()
FileOpen(ffr, File1, OpenMode.Random, OpenAccess.Read, OpenShare.LockRead, fLength)
lastmembNo = CInt(LOF(ffr)) \ fLength
For i = 1 To lastmembNo
FileGet(ffr, std, i)
>>Error 5 (unable to read beyond end of the stream) <<<
If Trim(memberID) = Trim(std.A) Then
sectionFound = True
end if
next i
Upvotes: 1
Views: 10088
Reputation:
I'm not sure about your example but this one however, works:
Public Class Form1
Const maxLenName = 30
Structure person
<VBFixedString(maxLenName)> Dim name As String
Dim age As Byte
End Structure
Private Sub Form1_Load(sender As [Object], e As EventArgs) Handles MyBase.Load
Dim entryIn As New person
Dim recordLen As Integer = Len(entryIn)
Dim entry As person
If FileIO.FileSystem.FileExists("test.raf") Then Kill("test.raf")
FileOpen(1, "test.raf", OpenMode.Random,,, recordLen)
'write
entry.name = LSet("Bill", maxLenName)
entry.age = 25
FilePut(1, entry, 6) 'write to 6th record
'read
Dim nRecords As Integer = LOF(1) \ recordLen
FileGet(1, entryIn, nRecords)
FileClose(1)
Dim personName As String = RTrim(entryIn.name)
Dim personAge As Byte = entryIn.age
MsgBox(personName & "'s age is " & personAge)
End Sub
End Class
Upvotes: 0
Reputation: 5393
OK, I think you should switch to the ".NET way", as follows:
Imports System.IO
Imports System.Xml
Public Class Form1
Public Const gintRecLen_CONST As Integer = 177
Class StdSections2
Private mstrA As String
Public Property A() As String
Get
Return mstrA
End Get
Set(ByVal value As String)
If value.Length <> 15 Then
Throw New Exception("Wrong size")
End If
mstrA = value
End Set
End Property
Private mstrB As String
Public Property B() As String
Get
Return mstrB
End Get
Set(ByVal value As String)
If value.Length <> 2 Then
Throw New Exception("Wrong size")
End If
mstrB = value
End Set
End Property
Public C(39) As Single
Public Shared Function FromBytes(byt() As Byte) As StdSections2
Dim output As New StdSections2
If byt.Length <> gintRecLen_CONST Then
Throw New Exception("Wrong size")
End If
For i As Integer = 0 To 14
output.mstrA &= Chr(byt(i))
Next i
For i As Integer = 15 To 16
output.mstrB &= Chr(byt(i))
Next i
For i As Integer = 0 To 39
Dim bytTemp(3) As Byte
output.C(i) = BitConverter.ToSingle(byt, 17 + 4 * i)
Next i
Return output
End Function
End Class
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim strFilename As String = "C:\Junk\Junk.txt"
Dim strMemberID As String = "foo"
Dim intRecCount As Integer = CInt(My.Computer.FileSystem.GetFileInfo(strFilename).Length) \ gintRecLen_CONST
Dim blnSectionFound As Boolean = False
Using fs As New FileStream(strFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
For intRec As Integer = 0 To intRecCount - 1
Dim intRecPos As Integer = gintRecLen_CONST * intRec
fs.Seek(intRecPos, SeekOrigin.Begin)
Dim byt(gintRecLen_CONST - 1) As Byte
fs.Read(byt, 0, gintRecLen_CONST)
Dim ss2 As StdSections2 = StdSections2.FromBytes(byt)
'MsgBox(ss2.A & ":" & ss2.C(3)) 'debugging
If strMemberID.Trim = ss2.A.Trim Then
blnSectionFound = True
Exit For
End If
Next intRec
End Using
MsgBox(blnSectionFound.ToString)
End Sub
End Class
We define a class called StdSections2 which uses .NET strings and an array of Singles. We use 0-based arrays everywhere. We load the file using the new FileStream object, and use the Seek() command to find the position we want. We then load raw bytes out of the file, and use Chr() and BitConverter.ToSingle() to convert the raw bytes into strings and singles.
Upvotes: 0
Reputation: 5393
Wow Freefile! That's a blast from the past!
I haven't really used the old OpenFile etc. file access methods in VB.NET, so I'm just speculating, but in .NET many of the variable types got changed in size. e.g. an Integer is now 32-bits (4 bytes), I think a Boolean is different, though a Single is still 4 bytes.
Also, strings in .NET are by default in Unicode, not ASCII, so you cannot rely on 1 character=1 byte in a .NET String variable. In fact, .NET actualy "JIT compiles" programs on the PC before running, so you can't really lay out structures in memory easily like the old days.
If you want to switch to the new "Stream" based objects, here's some code to get you started:
Dim strFilename As String = "C:\Junk\Junk.txt"
Dim strTest As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Call My.Computer.FileSystem.WriteAllText(strFilename, strTest, False)
Dim byt(2) As Byte
Using fs As New FileStream(strFilename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
fs.Seek(16, SeekOrigin.Begin)
fs.Read(byt, 0, 3)
Dim s As String = Chr(byt(0)) & Chr(byt(1)) & Chr(byt(2))
MsgBox(s)
fs.Seek(5, SeekOrigin.Begin)
fs.Write(byt, 0, 3)
End Using
Dim strModded As String = My.Computer.FileSystem.ReadAllText(strFilename)
MsgBox(strModded)
I wouldn't blame you for keeping the old method though: with the new method, you'll need to define a class, and then have a custom routine to convert from Byte() to the properties of the class. More work than simply loading bytes from the file into memory.
Upvotes: 1