升级VB6方法以读取随机访问文件到VB.net,无法读取超出流末尾的最后一条记录异常

问题描述 投票:0回答:2

我正在重新创建一个较旧的 VB6 程序,该程序读取使用 VB.net 中的另一个 VB6 程序创建的随机访问文件。 向后兼容性对于新的 VB.net 程序至关重要。 有数千个已编写的文件需要访问。当我在记事本++中打开它们时,每个文件都有五行,尽管我无法在记事本++中区分随机字符的头部或尾部。这些文件应该包含四个记录,所以我不确定第五行的用途。

我可以访问这两个程序的旧源代码。下面是VB6的读写方法。

VB6编写方法

Dim fi as long
fi = FreeFile
Open fileName For Random As #fi Len = 32000

Put #fi, 1, Loads
Put #fi, 2, Nodes
Put #fi, 3, Names
Put #fi, 4, Options

Close fi

VB6读取方法

Dim fi As Long      
fi = FreeFile
Open fileName For Random As #fi Len = 32000

Get #fi, 1, Loads
Get #fi, 2, Nodes
Get #fi, 3, Names
Get #fi, 4, Options

Close fi

VB,net读取方法(尝试)
在 VB.net 中,我使用以下内容来尝试读取相同的文件。

Dim fi As Integer = FreeFile()
FileOpen(fi, fileName, OpenMode.Random, RecordLength:=32000)

FileGet(fi, Loads, 1)
FileGet(fi, Nodes, 2)
FileGet(fi, Names, 3)
FileGet(fi, Options, 4)

FileClose(fi)

负载、节点、名称和选项在 VB6 中是[用户定义]类型,在 VB.net 中是结构。这些结构内部通常还有其他结构,而这些结构又包含更多结构。层次结构中的某些结构包含其他结构的数组,这些结构内部可能包含更多结构的数组。大多数结构字段都是单值或布尔值。 VB6 中有一些长整型,我在 VB.net 中将其转换为整数(以保持字节大小相同)。还有一些字符串字段。

当我尝试使用上面的 VB.net 读取方法时,它会获取负载、节点和名称的值。在

FileGet(fi, Options, 4)
行上,我得到: Systems.IO.EndOfStreamException: '无法读取超出流末尾的内容。'

看看上面的两种方法,它们的作用不应该是一样的吗?到底是什么原因导致 vb.net 中出现此异常?记录大小不是<= 32,000 bytes?


编辑

Options 基于typOptions,它使用typDesign 和typGeometry。 VB6:

Public Const numDebug = 12
Public Type typOptions
    optDesign As typDesign
    optDebug(numDebug) As Boolean
    optGeom As typGeometry
    optFrac As Single
End Type
Public Type typDesign
    mem01 As Single
    mem02 As Single
    mem03 As Single
    mem04 (3) As Single
End Type
Public Type typGeometry
    member1 As Single
    member2 As Single
    member3 As Single
    member4 As Single
    member5 As Single
    member6 As Single
    member7 As Single
End Type

VB.net

Public Const numDebug = 12
Public Structure typOptions
    Public optDesign As typDesign
    Public optDebug() As Boolean
    Public optGeom As typGeometry
    Public optFrac As Single
End Structure
Public Structure typDesign
    Public mem01 As Single
    Public mem02 As Single
    Public mem03 As Single
    Public mem04 () As Single
End Structure
Public Structure typGeometry
    Public member1 As Single
    Public member2 As Single
    Public member3 As Single
    Public member4 As Single
    Public member5 As Single
    Public member6 As Single
    Public member7 As Single
End Structure
' Elsewhere, when the form is loading:
ReDim Options.optDesign.mem04 (3)
ReDim Options.optDebug(numDebug)

编辑2

这些文件的文件大小似乎一致为 96,124 字节。选项仅存储 124 个字节,而不是 32,000 个。我尝试使用十六进制编辑器并添加“00”,直到有 128,000 字节(每条记录 32,000 字节 * 4 条记录),但随后我仍然遇到 无法读取超出流末尾的内容 异常。不过 128,000 字节的文件在 VB6 中确实可以工作。

我从 vbmigration.com 找到了一些关于此的信息:

VB6 和 VB.NET 在 UDT(VB.NET 用语中的结构)方式上有很大不同 从文件中读取或写入文件。不仅结构元素以不同的格式存储到文件中,而且两种语言还以不同的方式管理文件结束条件。在 VB6 中,即使操作会将文件指针移动到当前文件的长度之外,您也可以读取 UDT;在 VB.NET 中这样的操作会导致异常。

基于此,我本以为将文件设置为 128,000 字节而不是 96,124 可以修复无法读取超出流末尾的异常。

vb.net vb6 migration randomaccessfile
2个回答
3
投票
我认为问题在于您的结构是用动态数组声明的,但 VB6 结构是用固定长度数组声明的(撰写本文时的另一个答案也指出了这一点)。旧版二进制文件处理期望结构中的可变长度数组与二进制文件中的数组描述符相对应,因此尝试将二进制浮点值作为数组描述符读取会导致问题,这可能并不奇怪。

我认为最好的方法是在数组成员上使用

VBFixedArray

 属性。旧版二进制文件处理理解此属性,然后它应该正确读取文件。 (还有一个 
VBFixedString
 属性,用于描述 VBA 
Type
 中的固定长度字符串。)

结果会是这样的:

Public Structure typDesign Public mem01 As Single Public mem02 As Single Public mem03 As Single <VBFixedArray(3)> Public mem04() As Single End Structure
您可以在此处找到该属性的 .NET 6 文档:

https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.vbfixedarrayattribute?view=net-6.0

FileSystem

 命名空间中的 
Microsoft.VisualBasic
 类的文档中还对旧版二进制文件格式进行了一些讨论。


0
投票
您在这些 VB6 类型中看到的数组不是 SafeArray。它们实际上是向量,因此可以用基础变量的序列替换:在 Vb.Net 中,

x(3) As Single

 可以是 
x1 As Single
x2 As Single
 等。相反,类型 
中的
x() As Single
是一个 SafeArray,仅占用描述符使用的 4 个字节。

© www.soinside.com 2019 - 2024. All rights reserved.