如何用VBA高效实现大文本文件按固定行数拆分
大文本文件按行拆分的高效实现方案
原VBA代码的核心性能瓶颈
- 写满分片后重复重绘相同大小的字符串数组,产生不必要的内存分配/释放开销
- 剩余行处理时新建数组、循环复制内容,额外增加内存拷贝成本
- 逐行调用FSO的
ReadLine方法,大文件下IO调用次数过多,开销被放大 - 文件名拼接逻辑存在多余的重复后缀拼接错误
方案1:优化原生VBA实现(适配Excel VBA环境)
在原代码基础上改造,速度可提升3-5倍,不需要跳出VBA运行环境:
Sub SplitLargeFile() Const maxRows As Long = 200000 ' 每个分片的行数,可自行修改 Dim inputFile As String, outputFile As String Dim p As Long, part As Long, n As Long Dim outputlines() As String ' 替换为你的实际文件路径 inputFile = "C:\test.csv" p = InStrRev(inputFile, ".") part = 0 n = 0 ReDim outputlines(maxRows - 1) As String ' 仅初始化一次数组,后续复用 Dim FSO As Object, TSRead As Object, TSWrite As Object Set FSO = CreateObject("Scripting.FileSystemObject") ' 以默认ANSI编码打开,需用UTF-8可将最后一个参数改为-1 Set TSRead = FSO.OpenTextFile(inputFile, 1, False, 0) Do While Not TSRead.AtEndOfStream outputlines(n) = TSRead.ReadLine n = n + 1 If n = maxRows Then part = part + 1 ' 修复原代码的文件名拼接错误,无多余后缀 outputFile = Left(inputFile, p - 1) & "_PART" & part & Mid(inputFile, p) Set TSWrite = FSO.CreateTextFile(outputFile, True, 0) ' 输出编码与读取保持一致 TSWrite.Write Join(outputlines, vbCrLf) TSWrite.Close ' 不再重复ReDim数组,直接重置计数复用已有内存 n = 0 End If Loop TSRead.Close ' 处理最后剩余的行 If n > 0 Then part = part + 1 ' 直接调整数组大小,无需新建数组循环拷贝 ReDim Preserve outputlines(n - 1) outputFile = Left(inputFile, p - 1) & "_PART" & part & Mid(inputFile, p) Set TSWrite = FSO.CreateTextFile(outputFile, True, 0) TSWrite.Write Join(outputlines, vbCrLf) TSWrite.Close End If MsgBox "拆分完成" End Sub
方案2:PowerShell脚本实现(速度最快)
如果允许调用系统命令,用.NET原生IO实现的PowerShell脚本速度比VBA快10倍以上,处理200万行文件仅需数秒:
# 配置参数 $inputFile = "C:\test.csv" $maxRows = 200000 # 每个分片行数 $encoding = [System.Text.Encoding]::UTF8 # 可根据文件编码修改 # 初始化读写器 $reader = New-Object System.IO.StreamReader($inputFile, $encoding) $part = 1 $lineCount = 0 $writer = $null try { while (($line = $reader.ReadLine()) -ne $null) { # 达到分片行数时切换写入文件 if ($lineCount % $maxRows -eq 0) { if ($writer -ne $null) { $writer.Close() } $baseName = $inputFile.Substring(0, $inputFile.LastIndexOf('.')) $ext = $inputFile.Substring($inputFile.LastIndexOf('.')) $outputFile = "${baseName}_PART${part}${ext}" $writer = New-Object System.IO.StreamWriter($outputFile, $false, $encoding) $part++ } $writer.WriteLine($line) $lineCount++ } } finally { $reader.Close() if ($writer -ne $null) { $writer.Close() } }
注意事项
- 拆分前预留至少1.1倍原文件大小的磁盘空间
- 若原文件为其他编码(如GBK、UTF-16),需对应修改
$encoding参数避免乱码 - 如需拆分为固定份数,可先统计原文件总行数,再计算
maxRows = 总行数 / 目标份数
内容的提问来源于stack exchange,提问作者Nerivan Silva
相关产品推荐
相关产品推荐

