最近帮朋友写自动转xlsx到csv的脚本,尝试了aspose-cells和poi,前者闭源还混淆,后者速度慢很多,后来发现powershell脚本可以直接调用excel的api,最后就选择了powershell脚本
注意事项
- 此脚本需要电脑上安装Excel
- 此脚本需要电脑上安装高版本的powershell
使用方式
- 复制脚本到文件并修改文件后缀名到
.ps1
- 在脚本所在的文件夹中新建文件夹并重命名为
input
,把需要转换的文件放进去 - 右键脚本,选择
使用powershell7运行
或者 右键 -> 属性 修改打开方式为pwsh(在安装高版本powershell
的位置找),然后直接运行
脚本内容
chcp 65001 > nul Echo "将需要转换的文件放在input文件夹中, 输出的文件放在output文件夹中" if (!(Test-Path input)) { Mkdir input > $null } if (!(Test-Path output)) { Mkdir output > $null } $WorkingDir = (Get-Location).Path $Start = Get-Date -UFormat %s $Files = Get-ChildItem -Path "input" -Recurse | Where-Object { $_.Name -match ".*\.xls[xm]?" } $Files | ForEach-Object -Parallel { $Start = Get-Date -UFormat %s $Excel = New-Object -ComObject Excel.Application $WorkingDir = $using:WorkingDir $InFileName = $_.name $OutFileName = "$InFileName.csv" Echo "处理中... $InFileName -> $OutFileName" $OutFilePath = "$WorkingDir\output\$OutFileName" if (Test-Path $OutFilePath) { Remove-Item -Path $OutFilePath } $Excel.Workbooks.Open("$WorkingDir\input\$InFileName").Worksheets.Item(1).SaveAs("$OutFilePath", 62) $Time = (Get-Date -UFormat %s) - $Start Echo "处理完成 $OutFilePath 耗时${Time}秒" $Excel.Quit() } Get-Process -name Excel | Where-Object { $_.mainWindowTitle -eq "" } | ForEach-Object { Stop-Process $_.Id } $Time = (Get-Date -UFormat %s) - $Start $Count = $Files.Count Echo "全部文件处理完成, 共${Count}个文件, 耗时${Time}秒" Timeout -t 3
脚本会从input
文件夹中寻找后缀为.xls
或.xlsx
或.xlsm
的文件,将他的第一张表转换成csv
格式并保存到output
文件夹
SaveAs的第二个参数可以自行修改,参考
ps powershell还挺好用,比batch强多了
以及一个合并csv的脚本(合并表头)
chcp 65001 > nul Write-Output "将合并output文件夹中的csv文件, 输出到output.csv" if (!(Test-Path input)) { Mkdir input > $null } $WorkingDir = (Get-Location).Path $Start = Get-Date -UFormat %s $Files = Get-ChildItem -Path "output" -Recurse | Where-Object { $_.Name.EndsWith(".csv") } if ($Files.Count -le 1) { Timeout -t 3 exit } # 忽略的行数, 不包括表头 $Ignore = 0 $Flag = $true $Out = [System.IO.File]::OpenWrite("$WorkingDir\output.csv") $Writer = New-Object System.IO.StreamWriter($Out, [System.Text.UTF8Encoding]::new($true)) $Files | ForEach-Object { $Stream = [System.IO.File]::OpenRead("$WorkingDir\output\$($_.name)") $Reader = New-Object System.IO.StreamReader($Stream) # 忽略前n行 if ($Ignore -ne 0) { foreach ($__ in 1..$Ignore) { $Reader.ReadLine() > $null } } $Head = $Reader.ReadLine() # 表头行 if ($Flag) { $Flag = $false $Writer.WriteLine($Head) } while ($Line = $Reader.ReadLine()) { $Writer.WriteLine($Line) } $Reader.Close() $Stream.Close() } Write-Output "全部文件合并完成, 共$($Files.Count)个文件, 耗时$((Get-Date -UFormat %s) - $Start)秒" Timeout -t 3