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

VB.net无法读取CSV最后一条记录及双表关联更新实现咨询

解决VB.NET读取CSV最后一条记录及双表更新问题

首先说你遇到的CSV最后一条记录读不到的问题——看你提供的CSV格式,每条记录末尾都带分号,而且最后一行大概率没有换行符,这是很多人用普通StreamReader读取时会踩的坑。推荐用.NET自带的TextFieldParser(需要引用Microsoft.VisualBasic程序集),它专门为处理带引号、自定义分隔符的CSV设计,能完美解决漏读问题。


一、正确读取CSV(含最后一条记录)

核心思路

用TextFieldParser自动识别引号包裹的字段、自定义分隔符,同时它会正确处理无换行的最后一行。读取后过滤掉每条记录末尾分号产生的空字段,再转换为实体类方便后续处理。

示例代码

Imports Microsoft.VisualBasic.FileIO

' 定义CSV记录的实体类,和你的字段对应
Public Class CsvRecord
    Public Property Field1 As String
    Public Property Field2 As String
    Public Property Field3 As String
    Public Property Field4 As Integer
    Public Property Field5 As Date
    Public Property Field6 As String
End Class

' 读取CSV文件的方法
Private Function ReadCsvRecords(filePath As String) As List(Of CsvRecord)
    Dim records As New List(Of CsvRecord)()
    
    Using parser As New TextFieldParser(filePath)
        parser.TextFieldType = FieldType.Delimited
        parser.SetDelimiters(";") ' 设置分隔符为分号
        parser.HasFieldsEnclosedInQuotes = True ' 开启引号识别,必须开!
        
        ' 跳过第一行表头(FIELD1;FIELD2...)
        parser.ReadLine()
        
        ' 循环读取所有行,包括无换行的最后一行
        While Not parser.EndOfData
            Try
                Dim fields As String() = parser.ReadFields()
                ' 过滤掉末尾分号产生的空字段
                Dim validFields = fields.Where(Function(f) Not String.IsNullOrEmpty(f)).ToArray()
                
                ' 确保字段数量正确,再转换为实体
                If validFields.Length = 6 Then
                    Dim record As New CsvRecord With {
                        .Field1 = validFields(0),
                        .Field2 = validFields(1),
                        .Field3 = validFields(2),
                        .Field4 = Integer.Parse(validFields(3)),
                        .Field5 = Date.ParseExact(validFields(4), "M/d/yyyy", Nothing), ' 指定日期格式避免出错
                        .Field6 = validFields(5)
                    }
                    records.Add(record)
                End If
            Catch ex As MalformedLineException
                Console.WriteLine($"跳过格式错误的行:{parser.ErrorLine}")
            End Try
        End While
    End Using
    
    Return records
End Function

二、事务表与主表的更新逻辑

根据你的需求:两表以FIELD2为关联字段,事务表允许多条对应记录,主表仅保留一条。这里假设你用SQL Server数据库,用ADO.NET实现,核心逻辑是:

  • 主表:用MERGE语句实现"UPSERT"(存在则更新,不存在则插入),确保每个FIELD2唯一
  • 事务表:直接插入所有CSV记录,因为允许多条关联记录
  • 事务控制:用数据库事务确保主表和事务表的操作原子性,避免数据不一致

示例代码

Imports System.Data.SqlClient

Private Sub UpdateDatabase(records As List(Of CsvRecord), connectionString As String)
    Using conn As New SqlConnection(connectionString)
        conn.Open()
        ' 开启事务,要么全成功要么全回滚
        Using tran As SqlTransaction = conn.BeginTransaction()
            Try
                ' 1. 主表更新语句:MERGE实现UPSERT
                Dim masterSql As String = "
                    MERGE INTO MasterTable AS target
                    USING (SELECT @Field2, @Field1, @Field6) AS source(FIELD2, FIELD1, FIELD6)
                    ON target.FIELD2 = source.FIELD2
                    WHEN MATCHED THEN 
                        UPDATE SET FIELD1 = source.FIELD1, FIELD6 = source.FIELD6
                    WHEN NOT MATCHED THEN
                        INSERT (FIELD1, FIELD2, FIELD6) VALUES (source.FIELD1, source.FIELD2, source.FIELD6);
                "
                
                ' 2. 事务表插入语句
                Dim tranSql As String = "
                    INSERT INTO TransactionTable (FIELD1, FIELD2, FIELD3, FIELD4, FIELD5, FIELD6)
                    VALUES (@Field1, @Field2, @Field3, @Field4, @Field5, @Field6);
                "
                
                ' 遍历每条记录,先处理主表再插入事务表
                For Each record In records
                    ' 更新主表
                    Using masterCmd As New SqlCommand(masterSql, conn, tran)
                        masterCmd.Parameters.AddWithValue("@Field1", record.Field1)
                        masterCmd.Parameters.AddWithValue("@Field2", record.Field2)
                        masterCmd.Parameters.AddWithValue("@Field6", record.Field6)
                        masterCmd.ExecuteNonQuery()
                    End Using
                    
                    ' 插入事务表
                    Using tranCmd As New SqlCommand(tranSql, conn, tran)
                        tranCmd.Parameters.AddWithValue("@Field1", record.Field1)
                        tranCmd.Parameters.AddWithValue("@Field2", record.Field2)
                        tranCmd.Parameters.AddWithValue("@Field3", record.Field3)
                        tranCmd.Parameters.AddWithValue("@Field4", record.Field4)
                        tranCmd.Parameters.AddWithValue("@Field5", record.Field5)
                        tranCmd.Parameters.AddWithValue("@Field6", record.Field6)
                        tranCmd.ExecuteNonQuery()
                    End Using
                Next
                
                ' 提交事务
                tran.Commit()
                Console.WriteLine("数据更新完成!")
            Catch ex As Exception
                ' 出错回滚
                tran.Rollback()
                Console.WriteLine($"更新失败:{ex.Message}")
                Throw ' 抛出异常让上层处理
            End Try
        End Using
    End Using
End Sub

三、调用示例

Sub Main()
    Dim csvFilePath As String = "C:\YourCsvFile.csv"
    Dim dbConnString As String = "Server=你的服务器名;Database=你的数据库名;Integrated Security=True;"
    
    Try
        ' 读取CSV
        Dim csvRecords = ReadCsvRecords(csvFilePath)
        Console.WriteLine($"成功读取{csvRecords.Count}条记录")
        
        ' 更新数据库
        UpdateDatabase(csvRecords, dbConnString)
    Catch ex As Exception
        Console.WriteLine($"程序出错:{ex.Message}")
    End Try
End Sub

额外提示

  • 确保项目引用了Microsoft.VisualBasic程序集(右键项目→添加引用→程序集→找到并勾选)
  • 如果处理大量数据,事务表建议用SqlBulkCopy批量插入,效率会高很多
  • 日期格式如果有变化,记得修改Date.ParseExact的格式参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:47:29