Excel转CSV时百分比值被四舍五入,求PowerShell脚本解决方案
Excel转CSV时百分比列保留原始精度的PowerShell解决方案
问题背景
使用PowerShell将Excel文件转CSV时,发现百分比列的数值被自动四舍五入(例如4.55914%变成了4.56%),原始转换代码如下:
$extension = ((Split-Path $FilePath -Leaf).Split('.'))[1] if($extension -eq "xls" -or $extension -eq "xlsx") { Write-Host "Converting to CSV: $FilePath" -ForegroundColor Yellow $Excel = New-Object -ComObject Excel.Application $wb = $Excel.Workbooks.Open($FilePath, $false, $true) #$wb.WorkSheets(1).Columns.Item(3).NumberFormat = "Text" Write-Host (( $wb.WorkSheets(1).Columns.Item(3).NumberFormat )| Format-List | Out-String) $fileName = Split-Path $FilePath -Leaf $tempFile = Join-Path $tempFilesDir $fileName $FilePath = $tempFile -replace $extension, "csv" $ws = $wb.Worksheets.Item(1) $Excel.DisplayAlerts = $false $ws.SaveAs($FilePath, 6) Write-Host "CSV File Saved: $FilePath" -ForegroundColor Green $Excel.Quit() }
尝试过的方法及问题
- 尝试修改列的数字格式为
@#.########%,报错:Unable to set the NumberFormat property of the Range class - 尝试先取消工作表保护再修改格式:
仍出现相同错误。$wb.WorkSheets(1).Protect('',0,1,0,0,1,1,1) $wb.WorkSheets(1).Columns.Item(3).NumberFormat = "@##.######%" - 尝试设置为文本格式
$wb.WorkSheets(1).Columns.Item(3).NumberFormat = "Text",无报错但所有值变为T1900xt,不符合预期。
解决方案
方案1:直接读取单元格原始值,手动构建CSV
Excel中百分比本质是小数(比如4.55914%实际存储为0.0455914),可以直接读取单元格的Value2属性获取原始值,手动处理成带精度的百分比字符串后写入CSV,绕过Excel自动格式化的问题:
$extension = ((Split-Path $FilePath -Leaf).Split('.'))[1] if($extension -eq "xls" -or $extension -eq "xlsx") { Write-Host "Converting to CSV: $FilePath" -ForegroundColor Yellow $Excel = New-Object -ComObject Excel.Application $Excel.Visible = $false $wb = $Excel.Workbooks.Open($FilePath, $false, $true) $ws = $wb.Worksheets.Item(1) # 获取工作表已使用的数据范围 $usedRange = $ws.UsedRange $rowCount = $usedRange.Rows.Count $colCount = $usedRange.Columns.Count # 初始化CSV内容数组 $csvContent = @() # 遍历每一行数据 for ($i=1; $i -le $rowCount; $i++) { $rowData = @() # 遍历每一列 for ($j=1; $j -le $colCount; $j++) { $cell = $usedRange.Cells.Item($i, $j) if ($j -eq 3) { # 第3列为百分比列,根据实际列数调整 $rawValue = $cell.Value2 if ($rawValue -ne $null) { # 将原始小数转换为保留6位小数的百分比字符串 $formattedValue = "{0:F6}%" -f ($rawValue * 100) $rowData += "`"$formattedValue`"" } else { $rowData += "" } } else { # 处理其他列,包含特殊字符时添加引号 $cellValue = $cell.Value2 if ($cellValue -match '[" ,]') { $rowData += "`"$cellValue`"" } else { $rowData += $cellValue } } } # 将当前行数据拼接为CSV格式的字符串 $csvContent += $rowData -join ',' } # 生成CSV文件路径并写入内容 $fileName = Split-Path $FilePath -Leaf $tempFile = Join-Path $tempFilesDir $fileName $csvPath = $tempFile -replace $extension, "csv" $csvContent | Out-File -FilePath $csvPath -Encoding utf8 Write-Host "CSV File Saved: $csvPath" -ForegroundColor Green # 清理COM对象,避免内存泄漏 $wb.Close($false) $Excel.Quit() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($usedRange) | Out-Null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ws) | Out-Null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb) | Out-Null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel) | Out-Null [GC]::Collect() [GC]::WaitForPendingFinalizers() }
方案2:使用ImportExcel模块(更简洁)
若允许安装第三方模块,ImportExcel模块可直接读取Excel原始数据,无需处理复杂的COM对象操作:
- 先安装模块:
Install-Module -Name ImportExcel -Scope CurrentUser -Force
- 转换代码:
$extension = ((Split-Path $FilePath -Leaf).Split('.'))[1] if($extension -eq "xls" -or $extension -eq "xlsx") { Write-Host "Converting to CSV: $FilePath" -ForegroundColor Yellow $fileName = Split-Path $FilePath -Leaf $tempFile = Join-Path $tempFilesDir $fileName $csvPath = $tempFile -replace $extension, "csv" # 读取Excel数据,处理百分比列 $data = Import-Excel -Path $FilePath -WorksheetName 1 $data | ForEach-Object { # 替换为实际百分比列的列名,例如"Percentage" if ($_.Percentage) { $_.Percentage = "{0:F6}%" -f ($_.Percentage * 100) } } | Export-Csv -Path $csvPath -NoTypeInformation -Encoding utf8 Write-Host "CSV File Saved: $csvPath" -ForegroundColor Green }
关键说明
- Excel中百分比以小数形式存储(如
4.55914%对应0.0455914),需乘以100再格式化百分比字符串 - 使用
Value2属性可获取单元格原始值,避免读取格式化后的四舍五入结果 - 两种方案均绕过了Excel自带
SaveAs方法的自动格式化逻辑,确保数据精度
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

