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

VB.NET使用ClosedXML对比Excel单元格值的报错问题

VB.NET + ClosedXML 考勤程序调试问题解决

问题背景

我使用VB.NET结合ClosedXML开发考勤程序,需读取两个Excel文件的数据:

  • 第一个文件(ws2):指纹设备导出的考勤数据,包含员工ID、日期、工作日、首次签到、最后签退等字段
  • 第二个文件(ws3):员工排班表,按工作日列展示到岗、离岗时间

程序预期实现:

  1. 将ws3的所有列复制到新Excel文件(ws)
  2. 新增迟到/早退/缺勤列
  3. 统计每位员工的迟到、早退次数并写入对应行

但运行后,目标文件C:\Users\Dell\Downloads\Test\Test2.xlsx为空,调试时出现两类错误:

  1. 所有RowsUsed.Count调用存在语法错误
  2. 对比单元格值时提示Operator > (or <) is not defined for types XLCellValue and XLCellValue,例如代码行:
If ws2.Cell("E" + TotalFingerPrintsRows).Value < ws3.Cell("F" + TotalTimetableRows).Value Then

错误分析与修正方案

1. RowsUsed.Count语法错误

ClosedXML中RowsUsed是方法而非属性,必须加括号调用,正确写法为ws2.RowsUsed().Count()。原代码缺少括号,导致语法错误。

2. XLCellValue无法直接比较

XLCellValue是ClosedXML封装的单元格值类型,不支持直接用</>运算符比较时间或数值。需要通过.GetValue(Of T)方法转换为对应的数据类型(比如DateTime,因为是时间值),示例:

' 转换签到时间和排班到岗时间为DateTime类型
Dim signInTime As DateTime = ws2.Cell("D" & TotalFingerPrintsRows).GetValue(Of DateTime)()
Dim onDutyTime As DateTime = ws3.Cell("E" & TotalTimetableRows).GetValue(Of DateTime)()

' 正常比较
If signInTime > onDutyTime Then
    LateCount += 1
End If

3. 其他关键问题修正

  • 字符串拼接错误:VB.NET中字符串与数字拼接需用&而非+,"A" + TotalFingerPrintsRows会因类型不匹配报错,改为"A" & TotalFingerPrintsRows
  • 未保存工作簿:原代码未调用wb1.Save(),导致所有操作未写入磁盘,生成空文件。必须在所有数据处理完成后调用Save()
  • 循环逻辑冗余:原代码嵌套多层不必要的For Each循环(如遍历所有单元格),直接遍历RowsUsed()行集合即可,大幅简化逻辑
  • 循环范围错误:For TotalTimetableRows As Integer = 1 + ws3.RowsUsed.Count是无效范围,应改为1 To ws3.RowsUsed().Count()

修正后的核心代码片段

Public Class Form1
    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        Dim targetPath As String = "C:\Users\Dell\Downloads\Test\Test2.xlsx"
        ' 初始化目标工作簿,若文件不存在可改为New XLWorkbook()创建新文件
        Dim wb1 As IXLWorkbook = New XLWorkbook(targetPath)
        Dim ws As IXLWorksheet = wb1.Worksheet(1)

        ' 读取考勤数据文件
        Dim wb2 As IXLWorkbook = New XLWorkbook(TextBox1.Text)
        Dim ws2 As IXLWorksheet = wb2.Worksheet(1)
        ws2.Range("A:G").CopyTo(ws.Cell("A1"))

        ' 读取排班表文件
        Dim wb3 As IXLWorkbook = New XLWorkbook(TextBox2.Text)
        Dim ws3 As IXLWorksheet = wb3.Worksheet(1)
        ws3.Range("A:N").CopyTo(ws.Cell("H1"))

        ' 新增统计列标题
        ws.Cell("O1").Value = "迟到次数"
        ws.Cell("P1").Value = "早退次数"

        ' 遍历员工ID(假设范围1-250)
        For empId As Integer = 1 To 250
            Dim lateCount As Integer = 0
            Dim earlyLeaveCount As Integer = 0

            ' 遍历考勤数据行
            For Each attendanceRow In ws2.RowsUsed()
                ' 匹配员工ID和目标工作日(示例为Sunday)
                Dim currentEmpId As Integer = attendanceRow.Cell(1).GetValue(Of Integer)()
                Dim weekday As String = attendanceRow.Cell(3).GetValue(Of String)()

                If currentEmpId = empId And weekday.Equals("Sunday", StringComparison.OrdinalIgnoreCase) Then
                    ' 获取签到签退时间
                    Dim firstSignIn As DateTime = attendanceRow.Cell(4).GetValue(Of DateTime)()
                    Dim lastSignOut As DateTime = attendanceRow.Cell(5).GetValue(Of DateTime)()

                    ' 遍历排班表找对应员工的排班时间
                    For Each scheduleRow In ws3.RowsUsed()
                        Dim scheduleEmpId As Integer = scheduleRow.Cell(2).GetValue(Of Integer)()
                        If scheduleEmpId = empId Then
                            Dim onDutyTime As DateTime = scheduleRow.Cell(5).GetValue(Of DateTime)()
                            Dim offDutyTime As DateTime = scheduleRow.Cell(6).GetValue(Of DateTime)()

                            ' 统计迟到
                            If firstSignIn > onDutyTime Then
                                lateCount += 1
                            End If
                            ' 统计早退
                            If lastSignOut < offDutyTime Then
                                earlyLeaveCount += 1
                            End If
                        End If
                    Next
                End If
            Next

            ' 将统计结果写入目标表对应行(假设排班表员工ID在I列,即第9列)
            For Each targetRow In ws.RowsUsed()
                If targetRow.Cell(9).GetValue(Of Integer)() = empId Then
                    targetRow.Cell(15).Value = lateCount ' O列
                    targetRow.Cell(16).Value = earlyLeaveCount ' P列
                    Exit For
                End If
            Next
        Next

        ' 保存并释放资源
        wb1.Save()
        wb1.Dispose()
        wb2.Dispose()
        wb3.Dispose()
    End Sub
End Class

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 14:38:09