2023年8月22日 星期二

PowerShell 讀取檔案各種寫法利弊

PowerShell 讀取檔案各種寫法利弊

讀檔的方式其實蠻多的這邊大致介紹一下區別與效能影響



Get-Content

這是最常見的最快速的方法讀取出來是一個陣列物件,依照每行分配。

在絕大多數情況下是最方便快速的。

使用範例

Get-Content $Path

唯一的問題大概就是 Encoding 有限,只能用萬國碼或當前電腦編碼。還有性能沒有使用C#函式來得好。



[System.IO.File]::ReadAllLines()

遇到Encoding問題的時候首選的方案是這個,可以自由的設定編碼,而且有著較好的效能。

編碼問題大概比較容易遇到的狀況是

  1. 在舊版的 5.1 需要輸出不帶BOM的UTF8
  2. 非電腦編碼的其他語言

這兩種狀況都不是 Get-Content 能解決得,只能使用C#的函式

使用範例

$Enc = [Text.Encoding]::GetEncoding('UTF-8')
[System.IO.File]::ReadAllLines($Path, $Enc)

如果希望讀進來的不是陣列,使用 ReadAllText() 讀進來會是有換行的字串

要說缺點大概就是這東西不支持流,不支持流有個大問題是對於記憶體消耗比較重,假設今天要搬一個100G大小的文件,記憶體就得有100G才行,如果支持流可以讀一行寫一行自然對記憶體的負擔比較小了。



System.IO.StreamReader

這個大概是最好使的利器了,性能跟 ReadAllLines 一樣,而且支持流讀取與自訂 Encoding。檔案的指標移動也有支持,跟其他語言的讀取檔案差不多意思。

相比於前面這個函式是唯一可以解決缺少結尾空行的辦法了,前兩個其實都有個問題是會吃到一行結尾空行,因為for迴圈是在內部運行的,無權干預,這個可以自己寫能有效避開缺行的問題。

使用範例

$StreamReader = New-Object System.IO.StreamReader($Path, $Enc)
while ($null -ne ($line = $StreamReader.ReadLine())) {
    $line
}
if ($null -ne $StreamReader) { $StreamReader.Dispose() }

缺點也是一目了然,前後要開檔關檔還要寫 While 迴圈,對於快速測試來說這東西絕對不是首選。



Encoding編碼表查詢

最後附上各種常見編碼的查詢方法

# 日文::Shift-JIS (932)
[Text.Encoding]::GetEncoding('Shift-JIS')
# 簡體中文::GB2312 (936)
[Text.Encoding]::GetEncoding('GB2312')
# 繁體中文::BIG5 (950)
[Text.Encoding]::GetEncoding('BIG5')
# 萬國碼::UTF8 (65001)
[Text.Encoding]::GetEncoding('UTF-8')

# 萬國碼::UTF8-BOM (65001)
(New-Object System.Text.UTF8Encoding $True)
# 萬國碼::UTF8-NonBOM (65001)
(New-Object System.Text.UTF8Encoding $False)

# 當前系統編碼
PowerShell -Nop "& {return [Text.Encoding]::Default}"
# 當前 PowerShell 編碼
[Text.Encoding]::Default