最近帮朋友写自动转xlsx到csv的脚本,尝试了aspose-cells和poi,前者闭源还混淆,后者速度慢很多,后来发现powershell脚本可以直接调用excel的api,最后就选择了powershell脚本
注意事项
- 此脚本需要电脑上安装Excel
- 此脚本需要电脑上安装高版本的powershell
使用方式
- 复制脚本到文件并修改文件后缀名到
.ps1
- 在脚本所在的文件夹中新建文件夹并重命名为
input
,把需要转换的文件放进去 - 右键脚本,选择
使用powershell7运行
或者 右键 -> 属性 修改打开方式为pwsh(在安装高版本powershell
的位置找),然后直接运行
脚本内容
PowerShell
x
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的脚本(合并表头)
PowerShell
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