2021年4月24日 星期六

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

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

說明是對於 PowerShell 5.1 版本,從6版本以上預設 Out-File 預設就是不帶 BOM的。




解決方案 使用 C# 函式

在 ps 5.1 中唯一解法只有呼叫 C# 的函式,這裡有兩個可以用

[IO.File]::WriteAllText("TestFile.txt", "ㄅㄆㄇㄈ`r`n")


另一個是 Lines 區別只是這個會自動換行

[IO.File]::WriteAllLines("TestFile.txt", "ㄅㄆㄇㄈ")


如果要顯式指定編碼的話是這樣設置

$encoding = New-Object System.Text.UTF8Encoding $False
[IO.File]::WriteAllLines("TestFile.txt", "ㄅㄆㄇㄈ", $encoding)


還有另一個 IO.StreamWriter 的流處理函式,不過那寫起來會比較多行有需要自行參考這篇。
https://github.com/hunandy14/cvEncode/blob/master/cvEncoding.ps1#L160




解決方案 使用第三方函式

自己寫的處理函式,主要用於大量轉檔的。

irm bit.ly/cvEncoding|iex
"ㄅㄆㄇㄈ"| WriteContent "README.md" UTF8


有做過效能測試,使用管道行寫入的總時間約略快於用 WriteAllText 一次寫入整份檔案。這結果是蠻奇怪沒繼續深究,但總之速度是可接受的。

https://github.com/hunandy14/cvEncode/tree/master














------------------------以下舊文------------------------


解決方案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 參數也可以。



參考

沒有留言:

張貼留言