批次將所有Java 原始碼檔案快速轉成UTF-8 編碼的方法
文章推薦指數: 80 %
NET Framework 提供的 System.IO.File 類別,才能成功儲存以 UTF-8 編碼的文字檔案。
請注意: 以下程式執行到PowerShell 6+ 版本將會導致檔案內容整個 ...
←當Kubernetes或MicroK8s遇到DockerHub下載限制時的解決之道
使用Dockerfile建置容器映象(image)時應多注意「換行符號」帶來的影響→
最近公司接到一個老舊Java專案的升級改版案,由於原始碼全部都採用Big5編碼,導致在VisualStudioCode裡面無法成功編譯,雖然看了TroubleshootingGuideforEncodingIssues文件,也成功研究出維持Big5編碼也能持續開發的解決方案,但其實最好的解決方法,還是把所有Java原始碼變更為UTF-8才是王道。
今天我就來分享幾個不同的方法,幫助你快速將專案的所有原始碼從Big5轉換成UTF-8字集編碼!
由於透過命令列工具會牽涉到不同環境的問題,以下我分別透過幾種不同的環境來說明我所研究出來的轉換方法。
請務必看到最後,不然你可能會懊悔為什麼不看完!😅
使用PowerShell來快速轉換任意文字檔
由於PowerShell有兩個大的版本改變,兩者之間差異有點大,新版加入了許多語法與語言特性,所以寫法不太一樣!🔥
PowerShell6之後的版本
這段程式其實很簡單,就是先取得所有檔案清單,然後用指定的字集編碼讀入文字檔案,最後指定UTF-8寫入同一個檔案:
請注意:以下程式執行到PowerShell5.1之前的版本將會導致檔案內容整個亂掉,你一定要注意執行的PowerShell版本!你可以用$PSVersionTable.PSVersion查到版本資訊。
$sourceFolder='C:\Projects\ProjectA\src'
$filePatterns='*.java'
$DefaultEncoding=$PSDefaultParameterValues['*:Encoding']
$PSDefaultParameterValues['*:Encoding']='big5'
Get-ChildItem-Path$sourceFolder-Include$filePatterns-File-Recurse|ForEach-Object{
$filename=$_.VersionInfo.FileName
Write-Host"Convertingfrombig5toutf8:$filename..."-NoNewline
$filebody=Get-Content$filename-Raw
Set-Content-Value$filebody-Path$filename-Encodingutf8
Write-Host"Done"
}
$PSDefaultParameterValues['*:Encoding']=$DefaultEncoding
如果你的檔案非常多,可以考慮用以下這段程式,篩選檔案的速度快了6倍之多:
請注意$filePatterns的格式跟上一段不太一樣!
$sourceFolder='C:\Projects\ProjectA\src'
$filePatterns='.java'
$DefaultEncoding=$PSDefaultParameterValues['*:Encoding']
$PSDefaultParameterValues['*:Encoding']='big5'
Get-ChildItem-Path$sourceFolder-File-Recurse|where{$_.Extension-in$filePatterns}|ForEach-Object{
$filename=$_.VersionInfo.FileName
Write-Host"Convertingfrombig5toutf8:$filename..."-NoNewline
$filebody=Get-Content$filename-Raw
Set-Content-Value$filebody-Path$filename-Encodingutf8
Write-Host"Done"
}
$PSDefaultParameterValues['*:Encoding']=$DefaultEncoding
詳見:powershellperformance:Get-ChildItem-Includevs.Get-ChildItem|Where-Object
PowerShell5.1之前的版本
由於PowerShell5.1之前的版本完全不支援UTF-8編碼,僅支援UTF-8withBOM編碼,重點是Java編譯器並不支援任何以UTF-8withBOM編碼的*.java檔案,所以你不能使用PowerShell5.1之前提供的Set-Content來儲存檔案。
我們要藉助.NETFramework提供的System.IO.File類別,才能成功儲存以UTF-8編碼的文字檔案。
請注意:以下程式執行到PowerShell6+版本將會導致檔案內容整個亂掉,你一定要注意執行的PowerShell版本!你可以用$PSVersionTable.PSVersion查到版本資訊。
$sourceFolder='C:\Projects\ProjectA\src'
$filePatterns='*.java'
$Utf8NoBomEncoding=New-ObjectSystem.Text.UTF8Encoding$False
Get-ChildItem-Path$sourceFolder-Include$filePatterns-File-Recurse|ForEach-Object{
$filename=$_.VersionInfo.FileName
Write-Host"Convertingfrombig5toutf8:$filename..."
$filebody=Get-Content$filename-Encodingdefault
[System.IO.File]::WriteAllLines($filename,$filebody,$Utf8NoBomEncoding)
Write-Host"Done"
}
如果你的檔案非常多,可以考慮用以下這段程式,篩選檔案的速度快了6倍之多:
請注意$filePatterns的格式跟上一段不太一樣!
$sourceFolder='C:\Projects\ProjectA\src'
$filePatterns='.java'
$Utf8NoBomEncoding=New-ObjectSystem.Text.UTF8Encoding$False
Get-ChildItem-Path$sourceFolder-File-Recurse|where{$_.Extension-in$filePatterns}|ForEach-Object{
$filename=$_.VersionInfo.FileName
Write-Host"Convertingfrombig5toutf8:$filename..."
$filebody=Get-Content$filename-Encodingdefault
[System.IO.File]::WriteAllLines($filename,$filebody,$Utf8NoBomEncoding)
Write-Host"Done"
}
其實上述寫法有個嚴重的問題,哪就是我們「假設」所有的*.java檔案都是Big5編碼,如果不是,哪就慘了,檔案內容會整個亂掉!🔥
使用Linux常用工具來轉換任意文字檔
我最愛Linux的一個理由,就是它有無窮無盡各種優異的命令列工具,許多自動化的工作都可以透過這些工具完成,雖然有時候要寫出一些複雜的腳本並不容易,但是至少都「一定」寫的出來,問題也都能夠被解決。
這裡我將說明幾個我研究與撰寫的步驟,如果你只想要現成可用的腳本,直接看最後一個步驟即可:
取得指定檔案的字集編碼
其實這個步驟非常重要,因為我們並不知道資料夾下所有的*.java原始檔是否「真的」是Big5編碼,要是有一些混雜UTF-8的原始檔怎麼辦?
以下我用了find,file,cut,printf等工具,可以非常輕易的將每個檔案的編碼「猜」出來,雖然不一定會猜對,不過我想正確率十之八九不會錯的!
sourceFolder='/mnt/c/Projects/ProjectA/src'
forfin$(find$sourceFolder-typef-name'*.java'-o-name'*.properties'-o-name'*.txt');do
filemeta=`file-i$f`#Output:/src/Main.java:text/plain;charset=iso-8859-1
filename=`echo$filemeta|cut-d''-f1|cut-d':'-f1`
filetype=`echo$filemeta|cut-d''-f2|cut-d';'-f1`
encoding=`echo$filemeta|cut-d''-f3|cut-d'='-f2`
printf"%s\t%-10s\t%s\n""$filetype""$encoding""$filename"
done
正式利用iconv轉換檔案字集編碼
先用「人眼」判斷一下檔案編碼,我們可以知道其實iso-8859-1其實就是big5編碼(因為字集字碼範圍重疊的關係),所以我們加個判斷式就可以把檔案快速的轉過去了!
sourceFolder='/mnt/c/Projects/ProjectA/src'
forfin$(find$sourceFolder-typef-name'*.java'-o-name'*.properties'-o-name'*.txt');do
filemeta=`file-i$f`#Output:/src/Main.java:text/plain;charset=iso-8859-1
filename=`echo$filemeta|cut-d''-f1|cut-d':'-f1`
filetype=`echo$filemeta|cut-d''-f2|cut-d';'-f1`
encoding=`echo$filemeta|cut-d''-f3|cut-d'='-f2`
if["$encoding"=="iso-8859-1"]
then
printf"Convertingfrombig5toutf8:%s...""$filename"
iconv-fbig5-tutf8"$filename"|sponge"$filename"
printf"Done\n"
fi
done
這裡我使用了sponge工具,是個相當實用的小工具,大多Linux作業系統應該沒有內建。
若是Ubuntu系統請用sudoaptinstallmoreutils-y安裝。
若有Node.js也可以用npmi-gsponge安裝sponge全域工具套件。
其實判斷CJKmultibyteencodings(中日韓多位元編碼)的字碼範圍是非常困難的,因為他們都只用兩個Bytes代表一個「字」,因此不同的「字集」之間都有大量的重疊的字元,你想用程式去分析一份文件,想要藉此判斷出該文件的確切編碼,基本上誤判率非常高。
所以,我們在Windows作業系統的「控制台」中下才會有個Languagesfornon-Unicodeprograms的設定,專門用來給當程式無法正確判斷檔案字集時預設使用的字集!
但是在Linux底下沒有這種設定,所以你必須人工判斷。
但以我這次遇到的專案來說,專案中的檔案不可能出現「混和字集」的情況發生,因此我們只要判斷是否為utf8或non-utf8的字元即可,因此我會把程式改寫成以下這樣,只要檔案編碼「不是」用utf8編碼的檔案,全部都從big5轉成utf8即可!
sourceFolder='/mnt/c/Projects/ProjectA/src'
forfin$(find$sourceFolder-typef-name'*.java'-o-name'*.properties'-o-name'*.txt');do
filemeta=`file-i$f`#Output:/src/Main.java:text/plain;charset=iso-8859-1
filename=`echo$filemeta|cut-d''-f1|cut-d':'-f1`
filetype=`echo$filemeta|cut-d''-f2|cut-d';'-f1`
encoding=`echo$filemeta|cut-d''-f3|cut-d'='-f2`
if["$encoding"!="utf-8"]
then
printf"Convertingfrom%stoutf8:%s...""$encoding(big5)""$filename"
iconv-fbig5-tutf8"$filename"|sponge"$filename"
printf"Done\n"
fi
done
使用更正確的方法解決Windows轉換文字檔編碼的問題
其實你在Windows作業系統中根本找不到一個像樣的命令列工具可以幫我們判斷檔案編碼,但是在Win32API之中是有的,在.NETFramework裡面也有,但使用上就是沒有比用腳本語言整合來的方便。
所以我決定在Windows安裝一個file命令列工具,像Linux一樣方便的判斷檔案編碼!
你絕對沒想到的是,原來這個工具就被內建在GitforWindows安裝目錄中,預設路徑在C:\ProgramFiles\Git\usr\bin目錄下,你可以選擇要不要將此路徑加入到PATH環境變數中。
C:\ProgramFiles\Git\usr\bin\file.exe
有了這個file神隊友,我們的PowerShell就不會再跛腳了,以下是最終版本:
PowerShell6之後的版本
$sourceFolder='C:\Projects\ProjectA\src'
$filePatterns='*.java','*.txt','*.properties'
Get-ChildItem-Path$sourceFolder-Include$filePatterns-File-Recurse|ForEach-Object{
$filename=$_.VersionInfo.FileName
$encoding=$(file-i$filename)
|Select-String-Pattern"charset=(.*)$"-Encodingdefault
|foreach{$_.Matches[0].Groups[1].Value}
if($encoding-ne'utf-8'){
$DefaultEncoding=$PSDefaultParameterValues['*:Encoding']
$PSDefaultParameterValues['*:Encoding']='big5'
$filebody=Get-Content$filename-Raw
Write-Host"Convertingfrom$encoding(big5)toutf8:$filename..."-NoNewline
Set-Content-Value$filebody-Path$filename-Encodingutf8
Write-Host"Done"
$PSDefaultParameterValues['*:Encoding']=$DefaultEncoding
}
}
這裡我用了Select-String搭配RegularExpression來取得字集名稱,比較方便些。
PowerShell5.1之前的版本
$sourceFolder='C:\Projects\ProjectA\src'
$filePatterns='*.java','*.txt','*.properties'
$Utf8NoBomEncoding=New-ObjectSystem.Text.UTF8Encoding$False
Get-ChildItem-Path$sourceFolder-Include$filePatterns-File-Recurse|ForEach-Object{
$filename=$_.VersionInfo.FileName
$encoding=$(file-i$filename)|Select-String-Pattern"charset=(.*)$"-Encodingdefault|foreach{$_.Matches[0].Groups[1].Value}
if($encoding-ne'utf-8'){
$filebody=Get-Content$filename-Encodingdefault
Write-Host"Convertingfrom$encoding(big5)toutf8:$filename..."
[System.IO.File]::WriteAllLines($filename,$filebody,$Utf8NoBomEncoding)
Write-Host"Done"
$PSDefaultParameterValues['*:Encoding']=$DefaultEncoding
}
}
總結
判斷文字檔的編碼,其實沒有想像中簡單,雖然上述研究可以解決Big5轉UTF-8的問題,但專案中的檔案如果有用到超過不只一種DBCS(雙位元組字元集)編碼,例如大部分檔案是Big5編碼,但少部分檔案是GBK或GB2312編碼等,上述腳本一樣會有轉換失敗的問題,不過程式微調一下就可以轉換成功。
我這次遇到的狀況,主要是針對Java原始碼的檔案編碼問題做處理,解決之後,許多詭異的問題都可以迎刃而解,跨平台開發Java專案的問題也都消失的無影無蹤!👍
額外說個秘密,在GitforWindows之中,也有內建強大的iconv字碼轉換工具,你可以用"C:\ProgramFiles\Git\usr\bin\iconv.exe"-l查詢所有支援的字集,會用的人應該會很開心!😊
相關連結
分享幾個在Windows與Linux常見的編碼問題與解決方案|TheWillWillWeb
vscode-java-debug/Troubleshooting_encoding.mdatmain·microsoft/vscode-java-debug
Powershell:Change/SaveencodingHowtoconvertseveraltxtfilesUTF-8toUTF-8-BOM
encoding-UsingPowerShelltowriteafileinUTF-8withouttheBOM-StackOverflow
PowerShell5.1-Get-Content
PowerShell5.1-Set-Content
Variable-widthencoding-Wikipedia
file(1):determinefiletype-Linuxmanpage
LinuxFileCommand:HowtoDetermineFileTypeinLinux{+10Examples}
判斷字元編碼的工具(大多都判斷的不夠準確)
encoding-checker-npm
GetFileEncodingPowerShellScript
Convert-FileEncodingandGet-FileEncoding
相關文章
如何使用GoogleJavaFormat做到更決斷的Java原始碼編排風格
其實要在多套不同的IDE開發工具之間統一編碼風格(CodingStyle)真的不太容易,不同IDE之間的程式碼格式化能力不同,有的強、有的弱,自動排版完多多少少還是會有些差異,因此很難做到真
批次將所有Java原始碼檔案快速轉成UTF-8編碼的方法
最近公司接到一個老舊Java專案的升級改版案,由於原始碼全部都採用Big5編碼,導致在VisualStudioCode裡面無法成功編譯,雖然看了TroubleshootingGui
JenkinsonWindows心得分享(06):如何指定Mirror鏡像網站下載外掛
我們之前有個JenkinsCI/CD的導入顧問案,由於客戶是政府部門,客戶端的防火牆已經設定了無法連接到任何中國大陸的IP或URL,但是Jenkins的更新伺服器預設會判定來自台灣的
工商服務(廣告)
每月文章
2022
十月(5)
九月(17)
八月(10)
七月(11)
六月(4)
五月(10)
四月(5)
三月(9)
二月(9)
一月(15)
2021
十二月(12)
十一月(5)
十月(6)
九月(13)
八月(16)
七月(13)
六月(13)
五月(7)
三月(1)
二月(1)
2020
十二月(3)
十一月(1)
十月(3)
九月(7)
八月(7)
七月(9)
六月(2)
五月(5)
三月(4)
二月(5)
一月(4)
2019
十二月(7)
十一月(2)
十月(5)
九月(1)
六月(3)
四月(4)
三月(3)
二月(7)
一月(12)
2018
十二月(3)
十一月(1)
十月(4)
九月(12)
八月(4)
六月(2)
五月(3)
四月(6)
二月(1)
一月(2)
2017
十二月(2)
十月(3)
九月(4)
七月(1)
六月(1)
五月(1)
四月(1)
二月(3)
一月(4)
2016
十二月(4)
十一月(1)
十月(1)
九月(4)
八月(3)
七月(2)
五月(1)
四月(1)
三月(3)
二月(3)
一月(2)
2015
十二月(6)
十一月(4)
十月(3)
九月(5)
八月(1)
七月(4)
六月(2)
五月(3)
四月(1)
三月(1)
二月(3)
一月(2)
2014
十二月(3)
十一月(2)
十月(3)
九月(3)
八月(1)
七月(4)
六月(2)
五月(4)
四月(5)
三月(4)
二月(1)
一月(7)
2013
十二月(1)
十一月(8)
十月(1)
九月(2)
八月(4)
七月(5)
六月(8)
五月(9)
四月(8)
三月(10)
二月(9)
一月(10)
2012
十二月(4)
十一月(6)
十月(6)
九月(4)
八月(5)
七月(10)
六月(5)
五月(6)
四月(10)
三月(12)
二月(1)
一月(6)
2011
十二月(3)
十一月(7)
十月(8)
九月(14)
八月(15)
七月(10)
六月(10)
五月(11)
四月(11)
三月(13)
二月(14)
一月(13)
2010
十二月(13)
十一月(10)
十月(16)
九月(17)
八月(12)
七月(22)
六月(15)
五月(11)
四月(14)
三月(17)
二月(17)
一月(26)
2009
十二月(16)
十一月(18)
十月(18)
九月(23)
八月(20)
七月(26)
六月(24)
五月(21)
四月(26)
三月(30)
二月(27)
一月(26)
2008
十二月(30)
十一月(31)
十月(31)
九月(29)
八月(31)
七月(31)
六月(30)
五月(30)
四月(31)
三月(31)
二月(29)
一月(33)
2007
十二月(31)
十一月(37)
十月(13)
文章分類
.Net
(223)
.NETCore
(57)
Accessibility
(3)
Angular
(25)
AngularJS
(11)
ASP.NET
(223)
ASP.NET5
(3)
ASP.NETBlazor
(1)
ASP.NETCore
(37)
ASP.NETIdentity
(2)
ASP.NETMVC
(105)
ASP.NETWebAPI
(13)
AzureDevOps
(33)
C#
(127)
CloudComputing
(4)
CSS
(29)
DevOps
(22)
Docker
(28)
EntityFramework
(23)
Git
(31)
Golang
(2)
HTML5
(8)
IIS
(103)
Java
(26)
JavaScript
(108)
Jenkins
(7)
Kubernetes
(15)
LINQ
(36)
Linux
(114)
MicroK8s
(7)
MicrosoftAzure
(41)
MySQL
(15)
Office
(49)
Office365
(28)
Oracle
(10)
PHP
(25)
Scrum
(1)
Security
(66)
SQLServer
(127)
Subversion
(35)
SystemCenter
(2)
TFS
(6)
TFS2010
(10)
Tips
(190)
UnitTesting
(10)
Usability
(1)
VBA
(5)
VisualBasic
(5)
VisualStudio
(122)
VisualStudio11
(2)
VisualStudio2012
(10)
VisualStudio2013
(4)
VS2010Tips
(23)
Web
(172)
WebMatrix
(8)
Windows
(45)
Windows8
(14)
WindowsAzure
(18)
WindowsPhone7
(14)
介紹好用工具
(228)
心得分享
(88)
多奇快訊
(9)
系統管理
(368)
前端工程研究
(20)
專案管理
(8)
團隊合作
(9)
網路管理
(22)
延伸文章資訊
- 1Set-Content - PowerShell - SS64.com
set-content -encoding UTF8 will write a BOM if one is available in the source file, or if the sou...
- 2Byte order mark - Globalization - Microsoft Learn
- 3How to: Save and open files with encoding - Visual Studio (Windows)
- 4UTF-8 - MDN Web Docs Glossary: Definitions of Web-related terms
- 5PowerShell scripts for creating and reading test files with the ...
WE CAN'T BE SURE THAT THE ENCLOSING FILE WILL HAVE a UTF-8 BOM. # E.G., WHEN DOWNLOADED FROM A Gi...