You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB6随机访问文件读取时偶现记录重复问题求助

VB6随机访问文件读取偶现记录数据重复问题

问题现象

读取老旧VB6随机访问文件时,偶尔会出现一条记录的数据被复制到下一条记录的情况。实现相同功能的VB.Net文件流代码完全正常,且VB6的相关代码近期没做过任何修改。

VB6 读取代码

Property Let Location(ByVal Source As String)
    FileName = Source + ShortFileName
    FileNumber = FreeFile
    Open FileName For Random Access Read Write Shared As FileNumber Len = 200
    FileOpen = True
End Property

Public Sub Read(ByVal RecordNumber As Long)
    Get FileNumber, RecordNumber, FileData()
    RecordLocked = False
End Sub

VB .Net 读取代码

public string Location
{
    set
    {
        FileName = value + ShortFileName;
        strOriginalFilePath = value;
        fs = new FileStream(FileName, FileMode.Open, System.IO.FileAccess.ReadWrite, FileShare.ReadWrite, BufferLength, FileOptions.RandomAccess);
        IsFileOpen = true;
    }
}

public void Read(long RecordNumber)
{
    checked
    {
        bool flag = default(bool);
        while (!flag)
        {
            try
            {
                fs.Position = (RecordNumber - 1) * BufferLength;
                fs.Read(FileData, 0, BufferLength);
                flag = true;
            }
            catch (Exception projectError)
            {
                ProjectData.SetProjectError(projectError);
                Application.DoEvents();
                ProjectData.ClearProjectError();
            }
        }
    }
}

问题原因

  1. VB6缓存同步bug:VB6的Open For Random默认依赖系统文件缓存,当文件被其他进程(比如你的VB.Net程序)以共享模式访问时,缓存同步容易出现异常,导致读取到旧的缓存数据,表现为记录重复。
  2. 不必要的写权限:VB6代码用Access Read Write打开文件,但实际只做读取操作,多余的写权限会增加文件锁和缓存冲突的概率;VB.Net虽然也用了ReadWrite,但文件流的缓存处理逻辑更稳定。
  3. 数组残留数据:VB6的FileData()数组如果没在每次读取前重置,会残留上一次的读取数据,要是某次读取因为锁冲突没成功,旧数据就会被保留,造成重复的假象。

修复方案

1. 改成只读模式打开文件

既然只需要读取,把VB6的打开语句改成只读,减少冲突:

Open FileName For Random Access Read Shared As FileNumber Len = 200

2. 每次读取前重置数组

确保FileData数组没有残留数据,读取后强制同步缓存:

Public Sub Read(ByVal RecordNumber As Long)
    ' 重置数组长度为200字节(下标0-199)
    ReDim FileData(199)
    Get FileNumber, RecordNumber, FileData()
    ' 调用FileLen触发缓存同步,确保读到最新数据
    FileLen(FileName)
    RecordLocked = False
End Sub

3. 增加错误重试逻辑

VB6的Get遇到文件锁不会抛异常,可能返回错误数据,加个重试逻辑:

Public Sub Read(ByVal RecordNumber As Long)
    Dim retryCount As Integer
    retryCount = 0
    RecordLocked = True
    ' 最多重试3次
    Do While retryCount < 3
        On Error Resume Next
        ReDim FileData(199)
        Get FileNumber, RecordNumber, FileData()
        If Err.Number = 0 Then
            RecordLocked = False
            Exit Do
        End If
        Err.Clear
        retryCount = retryCount + 1
        DoEvents ' 等其他进程释放锁
    Loop
End Sub

4. 禁用VB6文件缓存(可选)

通过API强制禁用文件缓存,直接读磁盘:

Private Declare Function SetFileAttributes Lib "kernel32" Alias "SetFileAttributesA" (ByVal lpFileName As String, ByVal dwFileAttributes As Long) As Long
Private Const FILE_FLAG_NO_BUFFERING = &H20000000

Property Let Location(ByVal Source As String)
    FileName = Source + ShortFileName
    ' 设置文件无缓存属性
    SetFileAttributes FileName, FILE_FLAG_NO_BUFFERING
    FileNumber = FreeFile
    Open FileName For Random Access Read Shared As FileNumber Len = 200
    FileOpen = True
End Property

内容的提问来源于stack exchange,提问作者RandomTree

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 10:44:53