powershell 批量转换文本文件编码(GBK转UTF-8,支持多种不同编码的源文件)

powershell 批量转换文本文件编码(GBK转UTF-8)

01 前言

手头有一批SQL文件,通过某程序批量更新到Local DB。但是发现导进去后中文变乱码(一堆????),而且日志里头insert语句中文已经变成乱码,想来应该是编码的问题。一看SQL文件,GBK(系统默认编码)编码,于是想统一改成UTF-8编码。又不想去找各种工具了,直接用Powershell搞搞了。

02 正文

刚开始直接用powershell的内置命令get-contentset-content是挺方便的,但是结果一看,GBK转到了UTF-8 BOM 编码,不是很满意。但是也贴出来作为参考吧。

@echo off
powershell.exe -command "dir *.sql -R|foreach-object{(Get-Content $_.FullName -Encoding Default) | Set-Content $_.FullName -Encoding UTF8 };Write-Host 'Success...'"
pause

于是想到另外一个方法——.net。最后得到想要的UTF-8编码。

@echo off
powershell.exe -command "dir *.sql -R|foreach-object{[void][System.IO.File]::WriteAllBytes($_.FullName,[System.Text.Encoding]::Convert([System.Text.Encoding]::GetEncoding('GBK'),[System.Text.Encoding]::GetEncoding('UTF-8'),[System.IO.File]::ReadAllBytes($_.FullName)))};Write-Host 'Success...'"
pause

脚本使用说明

  • 脚本在powershell 5.1下测试通过
  • powershell脚本嵌入了CMD命令,所以另存为.bat,然后双击运行即可(递归遍历所有子目录,如果不需要,请将dir *.sql -R修改为dir *.sql
  • 如果是其他文本格式如csvtxt,请将脚本中dir *.sql修改为dir *.csvdir *.txt
  • 其他编码转换也可参考,做适当修改即可
  • 该脚本如果执行成功(不报错),请勿重复执行!否则可能会造成真的乱码。 (见后文更新部分,已自动判断源文件的编码)

1. 2024-05-09 18:48 更新

针对大文件的版本,且做了编码判断(自动识别转换前的编码;原编码与转换后编码一致的跳过):

@echo off
title Encoding Converter

REM 指定的一种文件类型(只支持一类)
set fileType=*.sql

REM 是否遍历子目录:需要遍历则设置为:-Recurse,否则置为空
REM set isRecurse=
set isRecurse=-Recurse

REM 转换前的文件编码(可以随便填一个,程序自动判断)
set fromEnc=GBK

REM 转换后的文件编码
set toEnc=UTF-8

REM 转换后的文件名前缀,默认与转换的文件在同一目录,可以为空(如果为空则直接覆盖原文件)
REM set prefix=
set prefix=temp_

powershell.exe -command "$files = dir %fileType% %isRecurse%; $prefix = '%prefix%'; $from = '%fromEnc%'; $to = '%toEnc%'; $e = [System.Text.Encoding]; $sr = [System.IO.StreamReader]; $sw = [System.IO.StreamWriter]; $isSame=[string]::IsNullOrEmpty($prefix); function getEnc($encName){if('UTF-8' -eq $encName.ToUpper()){return [System.Text.UTF8Encoding]::new($false);}return [System.Text.Encoding]::GetEncoding($encName); }; function getFileEnc($data) {[object[]]$res = @([System.Text.Encoding]::Default,$false);if($data[0] -eq 0x2B -and $data[1] -eq 0x2F -and $data[2] -eq 0x76) { return @([System.Text.Encoding]::UTF7,$true);}elseif($data[0] -eq 0xEF -and $data[1] -eq 0xBB -and $data[2] -eq 0xBF) { return @([System.Text.Encoding]::UTF8,$true);}elseif($data[0] -eq 0xFF -and $data[1] -eq 0xFE) { return @([System.Text.Encoding]::Unicode,$true);}elseif($data[0] -eq 0xFE -and $data[1] -eq 0xFF) { return @([System.Text.Encoding]::BigEndianUnicode,$true);}elseif($data[0] -eq 0 -and $data[1] -eq 0 -and $data[2] -eq 0xFE -and $data[3] -eq 0xFF) { return @([System.Text.Encoding]::UTF32,$true);}else{ [int]$charByteCounter = 1; [byte]$curByte = 0; for ($i = 0; $i -lt $data.Length; $i++) {$curByte = $data[$i];if ($charByteCounter -eq 1){if ($curByte -ge 0x80){ while (( ($curByte = ($curByte -shl 1)) -band 0x80) -ne 0) {$charByteCounter++; } if ($charByteCounter -eq 1 -or $charByteCounter -gt 6) {return $res; }}}else{if (($curByte -band 0xC0) -ne 0x80){ return $res;}$charByteCounter--;} } if ($charByteCounter -gt 1) {return $res; } return @([System.Text.Encoding]::UTF8,$false);}}; if($files.Count -lt 1){Write-Host 'No Files...';exit; }; Write-Host ('Begin:'+(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')); foreach($file in $files){ $newFile = (Join-Path -Path $file.DirectoryName -ChildPath ($prefix+$file.BaseName+$file.Extension)); if($isSame){ $newFile = (Join-Path -Path $file.DirectoryName -ChildPath ('TEMP_'+$file.BaseName+$file.Extension));}; $fromEnc = (getEnc -encName $from); $toEnc = (getEnc -encName $to); $fileEnc = (getFileEnc -data ([System.IO.File]::ReadAllBytes($file.FullName))); if($fileEnc[0].BodyName -eq $toEnc.BodyName -and $fileEnc[1] -eq $false){   Write-Host ($file.FullName+',no need to convert.');  continue; } if($fromEnc -ne $fileEnc[0]){ Write-Host ($file.FullName+',encoding should be:' + $fileEnc[0].BodyName); $fromEnc = (getEnc -encName $fileEnc[0].BodyName); } $srIn = $sr::new($file.FullName,$fromEnc); $swOut = $sw::new($newFile,$false,$toEnc,4096); while(($line = $srIn.ReadLine()) -ne $null){$swOut.WriteLine($line);} $srIn.Close();$swOut.Flush();$swOut.Close(); if($isSame){Move-Item -Path $newFile -Destination $file -Force};}; Write-Host ('Files:'+$files.Count+',success...'); Write-Host ('End:'+(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'));"
pause

脚本使用说明

  • 另存为.bat,然后双击运行即可
  • 相关参数根据需要修改

03 后记

欢迎留言交流~
---------END---------

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 23
    评论
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值