VB.NET使用ClosedXML对比Excel单元格值的报错问题
VB.NET + ClosedXML 考勤程序调试问题解决
问题背景
我使用VB.NET结合ClosedXML开发考勤程序,需读取两个Excel文件的数据:
- 第一个文件(ws2):指纹设备导出的考勤数据,包含员工ID、日期、工作日、首次签到、最后签退等字段
- 第二个文件(ws3):员工排班表,按工作日列展示到岗、离岗时间
程序预期实现:
- 将ws3的所有列复制到新Excel文件(ws)
- 新增迟到/早退/缺勤列
- 统计每位员工的迟到、早退次数并写入对应行
但运行后,目标文件C:\Users\Dell\Downloads\Test\Test2.xlsx为空,调试时出现两类错误:
- 所有
RowsUsed.Count调用存在语法错误 - 对比单元格值时提示
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
相关产品推荐
相关产品推荐

