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

Visual Basic .NET按双字符对替换字符串指定字符对的技术问题

处理FoxBase/dBASE III DBF文件的完整方案(Visual Basic WinForm)

核心问题解决

针对DBF文件中字符间存在0x00字节导致字符串截断的问题,实现双字节成对替换逻辑:仅替换成对出现的0x00为0x2A(即*),跳过单独的0x00字节。


1. DBF文件导入逻辑

通过OleDb连接读取DBF文件,直接读取字段原始字节数组(避免字符串截断),应用替换逻辑后转换为可编辑的字符串。

Imports System.Data.OleDb
Imports System.IO
Imports System.Text

Private Function LoadDBF(ByVal dbfPath As String) As DataTable
    Dim dt As New DataTable()
    Dim folderPath As String = Path.GetDirectoryName(dbfPath)
    Dim fileName As String = Path.GetFileName(dbfPath)

    ' dBASE III 连接字符串
    Using conn As New OleDbConnection($"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={folderPath};Extended Properties=dBASE III;")
        conn.Open()
        Using cmd As New OleDbCommand($"SELECT * FROM [{fileName}]", conn)
            Using reader As OleDbDataReader = cmd.ExecuteReader()
                dt.Load(reader)

                ' 处理目标列(替换为实际需要处理的列名,例如"TechColumn")
                Dim targetColName As String = "TechColumn"
                If dt.Columns.Contains(targetColName) Then
                    ' 重新读取原始字节
                    Using newReader As OleDbDataReader = cmd.ExecuteReader()
                        Dim colOrdinal As Integer = newReader.GetOrdinal(targetColName)
                        Dim rowIndex As Integer = 0
                        While newReader.Read()
                            If Not newReader.IsDBNull(colOrdinal) Then
                                ' 读取字段原始字节数组
                                Dim bufferSize As Integer = If(dt.Columns(targetColName).MaxLength > 0, dt.Columns(targetColName).MaxLength, 255)
                                Dim buffer(bufferSize - 1) As Byte
                                Dim bytesRead As Integer = newReader.GetBytes(colOrdinal, 0, buffer, 0, bufferSize)
                                Dim originalBytes As Byte() = New Byte(bytesRead - 1) {}
                                Array.Copy(buffer, originalBytes, bytesRead)

                                ' 应用双字节替换逻辑
                                Dim modifiedBytes As Byte() = ReplaceZeroPairs(originalBytes)
                                ' 转换为ASCII字符串(dBASE III默认单字节字符集)
                                dt.Rows(rowIndex)(targetColName) = Encoding.ASCII.GetString(modifiedBytes)
                            End If
                            rowIndex += 1
                        End While
                    End Using
                End If
            End Using
        End Using
    End Using
    Return dt
End Function

2. 双字节成对替换函数

严格按照需求,仅替换成对出现的0x00字节,跳过单独的0x00:

Private Function ReplaceZeroPairs(ByVal originalBytes As Byte()) As Byte()
    Dim result As New List(Of Byte)()
    Dim i As Integer = 0

    While i < originalBytes.Length
        ' 添加当前字节
        result.Add(originalBytes(i))

        ' 检查是否存在下一个字节(成对)
        If i + 1 < originalBytes.Length Then
            Dim nextByte As Byte = originalBytes(i + 1)
            ' 替换0x00为0x2A
            result.Add(If(nextByte = &H00, &H2A, nextByte))
            i += 2 ' 步长2,处理下一对
        Else
            ' 非成对字节,直接保留
            i += 1
        End If
    End While

    Return result.ToArray()
End Function

3. 数据编辑

直接使用DataGridView绑定导入后的DataTable,用户可直观编辑所有字段:

' 导入按钮点击事件
Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click
    Using ofd As New OpenFileDialog()
        ofd.Filter = "DBF Files (*.dbf)|*.dbf"
        If ofd.ShowDialog() = DialogResult.OK Then
            Dim dt As DataTable = LoadDBF(ofd.FileName)
            DataGridView1.DataSource = dt
            DataGridView1.AutoResizeColumns()
        End If
    End Using
End Sub

若不需要DataGridView,也可使用TextBox、ListBox等控件手动绑定数据,核心操作基于DataTable即可。


4. DBF文件导出逻辑

将编辑后的DataTable写入新的DBF文件,保持原表结构:

Private Sub SaveDBF(ByVal dt As DataTable, ByVal savePath As String)
    Dim folderPath As String = Path.GetDirectoryName(savePath)
    Dim fileName As String = Path.GetFileName(savePath)

    ' 确保目标文件夹存在
    If Not Directory.Exists(folderPath) Then
        Directory.CreateDirectory(folderPath)
    End If

    Using conn As New OleDbConnection($"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={folderPath};Extended Properties=dBASE III;")
        conn.Open()

        ' 1. 创建表结构
        Dim createSqlBuilder As New StringBuilder($"CREATE TABLE [{fileName}] (")
        For Each col As DataColumn In dt.Columns
            Dim colType As String = col.DataType.Name.ToLower() switch
                Case "string" : $"CHAR({col.MaxLength})"
                Case "int32", "int16" : "INTEGER"
                Case "datetime" : "DATE"
                Case "double" : "FLOAT"
                Case Else : "CHAR(255)"
            End switch
            createSqlBuilder.Append($"[{col.ColumnName}] {colType}, ")
        Next
        ' 移除末尾的逗号和空格
        createSqlBuilder.Length -= 2
        createSqlBuilder.Append(")")

        Using createCmd As New OleDbCommand(createSqlBuilder.ToString(), conn)
            createCmd.ExecuteNonQuery()
        End Using

        ' 2. 插入数据
        For Each row As DataRow In dt.Rows
            Dim insertSqlBuilder As New StringBuilder($"INSERT INTO [{fileName}] VALUES (")
            Dim valueList As New List(Of String)()

            For Each col As DataColumn In dt.Columns
                If row.IsNull(col) Then
                    valueList.Add("NULL")
                Else
                    Select Case col.DataType.Name.ToLower()
                        Case "string"
                            Dim strValue As String = row(col).ToString()
                            ' 转义SQL单引号
                            valueList.Add($"'{strValue.Replace("'", "''")}'")
                        Case "datetime"
                            valueList.Add($"'{DirectCast(row(col), DateTime).ToString("yyyyMMdd")}'")
                        Case Else
                            valueList.Add(row(col).ToString())
                    End Select
                End If
            Next

            insertSqlBuilder.Append(String.Join(", ", valueList))
            insertSqlBuilder.Append(")")

            Using insertCmd As New OleDbCommand(insertSqlBuilder.ToString(), conn)
                insertCmd.ExecuteNonQuery()
            End Using
        Next
    End Using
End Sub

' 导出按钮点击事件
Private Sub btnExport_Click(sender As Object, e As EventArgs) Handles btnExport.Click
    If DataGridView1.DataSource Is Nothing Then
        MessageBox.Show("请先导入DBF文件!")
        Return
    End If

    Using sfd As New SaveFileDialog()
        sfd.Filter = "DBF Files (*.dbf)|*.dbf"
        If sfd.ShowDialog() = DialogResult.OK Then
            Dim dt As DataTable = DirectCast(DataGridView1.DataSource, DataTable)
            SaveDBF(dt, sfd.FileName)
            MessageBox.Show("DBF文件导出成功!")
        End If
    End Using
End Sub

注意事项

  • 确保系统安装了Microsoft Jet OLEDB 4.0(Win10/11需手动安装);
  • 替换代码中的TechColumn为实际需要处理的列名;
  • 如需导出时还原0x2A为0x00,可在导出逻辑中添加字节替换代码;
  • DBF字段长度需与原文件一致,避免数据截断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 13:37:07