2021年4月24日 星期六

PowerShell 如何輸出 不帶BOM的 UTF-8 檔案

PowerShell 如何輸出 不帶BOM的 UTF-8 檔案

本文的說明都是針對 PowerShell 5.1 版本,從6版本開始就沒這個問題了,直接 Out-File 就是 UTF8 了。

這個問題很坑,現在版本的Windows10還在用舊版的 PowerShell 5.1 導致輸出UTF8檔案的時候是帶有BOM的。

個人認為最好的解決辦法是直接更新到 PowerShell7.0 就直接什麼問題都沒有了,預設輸出就是不帶BOM的UTF8。



解決方案1 - ASCII

簡單粗暴的的方法,直接寫入 ASCII 就好了。
不能寫中文,但可以記下來應急的時候很好用。

$FileContent = "only english content"
$dstPath = [Environment]::GetFolderPath("Desktop")
$FileContent | Out-File -Encoding ASCII "$dstPath\utf8.txt"

解決方案2 - WriteAllLines

這個方法就不會出問題了,不過是從記憶體一次寫入大小有限。

$FileContent = "中文UTF8內容"
$dstPath = [Environment]::GetFolderPath("Desktop")
$Enc = (New-Object System.Text.UTF8Encoding $False)
[System.IO.File]::WriteAllLines("$dstPath\utf8.txt", $FileContent, $Enc);

解決方案3 - Out-FileUtf8NoBom

這個函式比較能從根本解決問題

載入很簡單,直接打這行就可以把方法載入了

irm https://gist.github.com/mklement0/8689b9b5123a9ba11df7214f82a673be/raw/Out-FileUtf8NoBom.ps1 | iex

再來使用方法和原本的 Out-File 差不多 (不過原作者並沒有實現全部的接口)

$FileContent = "中文UTF8內容"
$dstPath = [Environment]::GetFolderPath("Desktop")
$FileContent | Out-FileUtf8NoBom $dstPath\utf8.txt

這樣就能簡單生成一個不帶BOM的UTF8文件了。

原作者:https://gist.github.com/mklement0/8689b9b5123a9ba11df7214f82a673be


 

如何安裝 Out-FileUtf8NoBom 到電腦上

上面的指令關掉之後副程式就沒了,每次都要重新載入,如果想要用久的安裝到電腦上,可以使用下面指令。

# 調整權限
Set-ExecutionPolicy RemoteSigned -scope CurrentUser

# 創建初始化腳本檔
if (!(Test-Path -Path $PROFILE )) { New-Item -Type File -Path $PROFILE -Force }

# 從gist載入函式
irm https://gist.github.com/mklement0/8689b9b5123a9ba11df7214f82a673be/raw/Out-FileUtf8NoBom.ps1 | iex

# 把函式寫入腳本檔
"`nfunction Out-FileUtf8NoBom {`n${function:Out-FileUtf8NoBom}`n}" | Out-FileUtf8NoBom -Append $PROFILE

這樣就永久安裝到電腦了,隨時都可以用 Out-FileUtf8NoBom 函式了


其他編碼轉換

其他編碼的轉法可以參考這裡的查詢方法

# 直接存取只有預設與UTF8 (可以按TAB一個一個查)
 [Text.Encoding]::Default
[Text.Encoding]::UTF8

# 用名稱查詢
[Text.Encoding]::GetEncoding('UTF-8')
[Text.Encoding]::GetEncoding('BIG5')
[Text.Encoding]::GetEncoding('Shift_JIS')

# 用編號查詢
[Text.Encoding]::GetEncoding(65001)
[Text.Encoding]::GetEncoding(950)
[Text.Encoding]::GetEncoding(932)

實際使用時像這樣

# 編碼
$Enc_Default = [Text.Encoding]::Default
$Enc_UTF8_BOM = [Text.Encoding]::GetEncoding(65001)
$Enc_UTF8 = New-Object System.Text.UTF8Encoding $False
$Enc_BIG5 = [Text.Encoding]::GetEncoding(950)
$Enc_SIFT = [Text.Encoding]::GetEncoding(932)

# 讀寫檔案
$Encoding = $Enc_UTF8
[System.IO.File]::ReadAllLines($Path, $Content, $Encoding);
[System.IO.File]::WriteAllLines($Path, $Content, $Encoding);


UTF8 比較特別要用別的寫法否則會變成帶有BOM的檔案,或者是直接在WriteAllLines() 函數上省略最後面的 $Encoding 參數也可以。



參考

沒有留言:

張貼留言