2012-09-17 76 views
2

我正在尝试读取随机访问文件,但我在第一个文件Error 5 (unable to read beyond end of the stream)上收到以下错误。我不确定我在这里做错了什么,我该如何解决这个问题?如何正确读取VB.NET中的随机访问文件

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 

回答

1

Wow Freefile!这是过去的一个爆炸!

我在VB.NET中并没有真正使用旧的OpenFile等文件访问方法,所以我只是猜测,但在.NET中,许多变量类型的大小发生了变化。例如Integer现在是32位(4字节),我认为布尔值是不同的,尽管Single仍然是4个字节。

此外,.NET中的字符串默认情况下是Unicode,而不是ASCII,因此您不能在.NET字符串变量中依赖1个字符= 1个字节。实际上,在运行之前,.NET真正的“JIT编译”程序在PC上,所以你不能像以前一样容易地将结构布置在内存中。

如果你想切换到新的“流”为基础的对象,这里的一些代码,让你开始:

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) 

我不会怪你保持旧的方法,但:用新的方法,您需要定义一个类,然后有一个自定义例程将Byte()转换为该类的属性。比简单地将文件中的字节加载到内存中更多的工作。

+0

其实,我不知道你是否能结合BinaryReader.ReadInt16等使用FileStream.Seek()?嗯.... – SSS

+0

BitConverter类可能也有帮助:http://msdn.microsoft.com/en-us/library/system.bitconverter.aspx – SSS

+0

感谢您的详细评论,我绝对计划开始更新不久的将来,我一定会把你的建议考虑在内。由于我仍然只是一个初学者,我只是想了解并修复我目前的错误。你有什么想法,为什么我的原始错误说,它不能阅读超过流的末尾?我不确定我做错了什么? – Matthew

0

OK,我想你应该切换到“.NET方式”,具体如下:

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 

我们定义了一个名为StdSections2类使用.NET字符串和单打的数组。我们在任何地方使用基于0的数组。我们使用新的FileStream对象加载文件,并使用Seek()命令找到我们想要的位置。然后,我们将原始字节加载到文件外,然后使用Chr()和BitConverter.ToSingle()将原始字节转换为字符串和单个字节。

0

我不知道你的例子,但然而,这一个工程:

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