操作excel表,实现字段替换以及全角和半角的转换

103 阅读4分钟

对于数据量较小的情况,使用串行处理的方法(ProcessSheetOriginal)可能更有效率,因为:

  1. 较少的开销:串行处理避免了线程管理和同步的开销。创建和管理线程需要一定的系统资源,对于数据量不大的任务,这些开销可能会抵消并行处理带来的性能提升。
  2. 数据传输和 IO:处理较小的数据集时,数据的读取和写入操作可能会占据大部分时间。串行处理方法直接在内存中操作数据,减少了对工作表的频繁读取和写入,从而可能提高效率。
  3. 线程调度:操作系统在并行处理中需要调度多个线程,这可能会引入上下文切换的开销。如果数据量不大,并行处理的调度开销可能会超过实际的处理时间,导致整体性能降低。

小数据集中的串行处理优势

  1. 简洁性:串行处理代码通常更简洁,逻辑更易于理解和维护。
  2. 性能:对于小规模的数据处理,串行代码往往能够提供足够的性能,因为操作系统的线程管理开销在这种情况下可能会超过并行处理带来的性能改进。

大数据集中的并行处理优势

  1. 并行计算:当数据量大到足够影响处理时间时,并行处理能够将工作分解到多个处理器核心上,加快整体处理速度。
  2. 提升效率:对于数据量非常大的任务,并行处理能够显著提高处理效率,特别是在处理复杂计算和大量数据时。

代码示例

0. 引入命名空间

Imports System.Windows.Forms
Imports System.Data
Imports Microsoft.Data.SqlClient
Imports Microsoft.Office.Interop.Excel

1. excel处理方法

串行处理代码

' 花费时间 00:00:00.0375333 (IsRunning = False)
Public Shared Sub ProcessSheetOriginal(sheet As Worksheet)
    Dim stopwatch As New Stopwatch()
    stopwatch.Start()

    Dim usedRange As Range = sheet.UsedRange
    Dim values As Object(,) = usedRange.Value2
    Dim rows As Integer = values.GetLength(0)
    Dim cols As Integer = values.GetLength(1)

    For i As Integer = 1 To rows
        For j As Integer = 1 To cols
            If values(i, j) IsNot Nothing AndAlso TypeOf values(i, j) Is String Then
                Dim originalValue As String = values(i, j).ToString()
                Dim convertedValue As String = ConvertFullWidthAndHalfWidth(originalValue)

                ' 只有在值发生变化时才进行赋值
                If Not originalValue.Equals(convertedValue) Then
                    values(i, j) = convertedValue
                End If
            End If
        Next
    Next

    usedRange.Value2 = values

    stopwatch.Stop()
    Console.WriteLine($"ProcessSheetOriginal 执行时间: {stopwatch.ElapsedMilliseconds} ms")
End Sub

并行处理代码

' 花费时间 00:00:00.0588076 (IsRunning = False)
Public Shared Sub ProcessSheetParallel(sheet As Worksheet)
    Dim stopwatch As New Stopwatch()
    stopwatch.Start()

    Dim usedRange As Range = sheet.UsedRange
    Dim values As Object(,) = usedRange.Value2
    Dim rows As Integer = values.GetLength(0)
    Dim cols As Integer = values.GetLength(1)

    ' 使用 Parallel.For 实现并行处理
    Parallel.For(1, rows + 1, Sub(i)
                                  For j As Integer = 1 To cols
                                      If values(i, j) IsNot Nothing AndAlso TypeOf values(i, j) Is String Then
                                          Dim originalValue As String = values(i, j).ToString()
                                          Dim convertedValue As String = ConvertFullWidthAndHalfWidth(originalValue)

                                          ' 只有在值发生变化时才进行赋值
                                          If Not originalValue.Equals(convertedValue) Then
                                              values(i, j) = convertedValue
                                          End If
                                      End If
                                  Next
                              End Sub)

    usedRange.Value2 = values

    stopwatch.Stop()
    Console.WriteLine($"ProcessSheetParallel 执行时间: {stopwatch.ElapsedMilliseconds} ms")
End Sub

2. 实际修改方法

        Shared Function ConvertFullWidthAndHalfWidth(text As String) As String
            ' 替换全角空格为半角空格
            text = text.Replace(ChrW(12288), ChrW(32)) ' 全角空格 (U+3000) 转为 半角空格 (U+0020)

            ' 转换全角英文字符为半角英文字符,并将假名字符转换为全角
            Dim sb As New System.Text.StringBuilder()
            For Each c As Char In text
                Dim code As Integer = AscW(c)
                If code >= 65281 AndAlso code <= 65374 Then
                    ' 全角字符转为半角字符
                    sb.Append(ChrW(code - 65248))
                ElseIf code >= 65382 AndAlso code <= 65439 Then
                    ' 半角假名字符转为全角假名字符
                    sb.Append(ChrW(code + 65248))
                Else
                    sb.Append(c)
                End If
            Next
            Return sb.ToString()
        End Function

3. 案例全部代码

Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Diagnostics
Imports System.Threading.Tasks

Public Class ExcelProcessor

    ' 假设这些方法已经定义在你的类中
    Public Shared Sub ProcessSheetOriginal(sheet As Excel.Worksheet)
        Dim stopwatch As New Stopwatch()
        stopwatch.Start()

        Dim usedRange As Excel.Range = sheet.UsedRange
        Dim values As Object(,) = usedRange.Value2
        Dim rows As Integer = values.GetLength(0)
        Dim cols As Integer = values.GetLength(1)

        For i As Integer = 1 To rows
            For j As Integer = 1 To cols
                If values(i, j) IsNot Nothing AndAlso TypeOf values(i, j) Is String Then
                    Dim originalValue As String = values(i, j).ToString()
                    Dim convertedValue As String = ConvertFullWidthAndHalfWidth(originalValue)

                    ' 只有在值发生变化时才进行赋值
                    If Not originalValue.Equals(convertedValue) Then
                        values(i, j) = convertedValue
                    End If
                End If
            Next
        Next

        usedRange.Value2 = values

        stopwatch.Stop()
        Console.WriteLine($"ProcessSheetOriginal 执行时间: {stopwatch.ElapsedMilliseconds} ms")
    End Sub

    Public Shared Sub ProcessSheetParallel(sheet As Excel.Worksheet)
        Dim stopwatch As New Stopwatch()
        stopwatch.Start()

        Dim usedRange As Excel.Range = sheet.UsedRange
        Dim values As Object(,) = usedRange.Value2
        Dim rows As Integer = values.GetLength(0)
        Dim cols As Integer = values.GetLength(1)

        ' 使用 Parallel.For 实现并行处理
        Parallel.For(1, rows + 1, Sub(i)
                                      For j As Integer = 1 To cols
                                          If values(i, j) IsNot Nothing AndAlso TypeOf values(i, j) Is String Then
                                              Dim originalValue As String = values(i, j).ToString()
                                              Dim convertedValue As String = ConvertFullWidthAndHalfWidth(originalValue)

                                              ' 只有在值发生变化时才进行赋值
                                              If Not originalValue.Equals(convertedValue) Then
                                                  values(i, j) = convertedValue
                                              End If
                                          End If
                                      Next
                                  End Sub)

        usedRange.Value2 = values

        stopwatch.Stop()
        Console.WriteLine($"ProcessSheetParallel 执行时间: {stopwatch.ElapsedMilliseconds} ms")
    End Sub

    Public Shared Function ConvertFullWidthAndHalfWidth(text As String) As String
        ' 替换全角空格为半角空格
        text = text.Replace(ChrW(12288), ChrW(32)) ' 全角空格 (U+3000) 转为 半角空格 (U+0020)

        ' 转换全角英文字符为半角英文字符
        Dim sb As New System.Text.StringBuilder()
        For Each c As Char In text
            Dim code As Integer = AscW(c)
            If code >= 65281 AndAlso code <= 65374 Then
                ' 全角字符转为半角字符
                sb.Append(ChrW(code - 65248))
            Else
                sb.Append(c)
            End If
        Next
        Return sb.ToString()
    End Function

    Public Sub TestMethods()
        ' 创建 Excel 应用程序实例
        Dim excelApp As New Excel.Application()
        Dim workbook As Excel.Workbook = excelApp.Workbooks.Open("C:\Path\To\Your\Workbook.xlsx")
        Dim sheet As Excel.Worksheet = workbook.Sheets(1) ' 获取第一个工作表

        ' 测试串行处理
        Console.WriteLine("Testing ProcessSheetOriginal...")
        ProcessSheetOriginal(sheet)

        ' 测试并行处理
        Console.WriteLine("Testing ProcessSheetParallel...")
        ProcessSheetParallel(sheet)

        ' 清理和保存工作簿
        workbook.Save()
        workbook.Close()
        excelApp.Quit()

        ' 释放 COM 对象
        ReleaseObject(sheet)
        ReleaseObject(workbook)
        ReleaseObject(excelApp)
    End Sub

    Private Sub ReleaseObject(ByVal obj As Object)
        Try
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
            obj = Nothing
        Catch ex As Exception
            obj = Nothing
        Finally
            GC.Collect()
        End Try
    End Sub
End Class

说明

  1. ConvertFullWidthAndHalfWidth: 用于全角和半角字符转换的辅助方法。
  2. ProcessSheetOriginal: 串行处理工作表数据的方法。
  3. ProcessSheetParallel: 并行处理工作表数据的方法。
  4. TestMethods: 测试方法,创建 Excel 应用程序实例,打开指定的工作簿,调用串行和并行处理方法,并保存和关闭工作簿。
  5. ReleaseObject: 用于释放 COM 对象的辅助方法,确保在使用完 Excel 对象后进行正确的清理。

运行测试

  • 你需要将 "C:\Path\To\Your\Workbook.xlsx" 替换为你实际的 Excel 文件路径。
  • 确保你的 Excel 环境配置正确,并且已经引用了必要的 Excel Interop 库。

这段代码将测试并比较串行处理和并行处理在实际数据上的执行时间。