【问题标题】:Read UTF-8 files correctly with PowerShell使用 PowerShell 正确读取 UTF-8 文件
【发布时间】:2014-04-01 14:49:36
【问题描述】:

以下情况:

  • PowerShell 脚本使用 UTF-8 编码创建文件
  • 用户可能会也可能不会编辑文件,可能会丢失 BOM,但应将编码保持为 UTF-8,并可能更改行分隔符
  • 同一个 PowerShell 脚本读取文件,添加更多内容并将其全部以 UTF-8 格式写回同一个文件
  • 这可以重复多次

对于Get-ContentOut-File -Encoding UTF8,我无法正确阅读它。它在它之前写的 BOM 上磕磕绊绊(把它放在内容中,破坏了我的解析正则表达式),不使用 UTF-8 编码,甚至删除了原始内容部分中的换行符。

我需要一个可以读取任何具有 UTF-8 编码的文件、忽略和删除 BOM 并且不修改内容的函数。我应该使用什么?

更新

我添加了一个小测试脚本,显示我正在尝试做什么以及会发生什么。

# Read data if exists
$data = ""
$startRev = 1;
if (Test-Path test.txt)
{
    $data = Get-Content -Path test.txt
    if ($data -match "^[0-9-]{10} - r([0-9]+)")
    {
        $startRev = [int]$matches[1] + 1
    }
}
Write-Host Next revision is $startRev

# Define example data to add
$startRev = $startRev + 10
$newMsgs = "2014-04-01 - r" + $startRev + "`r`n`r`n" + `
    "Line 1`r`n" + `
    "Line 2`r`n`r`n"

# Write new data back
$data = $newMsgs + $data
$data | Out-File test.txt -Encoding UTF8

运行几次后,应该在文件的开头添加新的部分,不应以任何方式更改现有内容(当前会丢失换行符),并且不应在末尾添加新的行文件(似乎有时会发生)。

相反,第二次运行给了我一个错误。

【问题讨论】:

  • 我对整个编码主题不太了解,但是如果 BOM 被删除,您是否必须重新注入 BOM 才能正确读取它?我对这个问题有点困惑。为什么要删除 UTF-8 BOM?
  • 我的文本编辑器很笨,将其删除。无论如何,您永远不知道文本编辑器对 UTF-8 文件做了什么。我的脚本应该足够聪明来处理它。就像 StreamReader 类一样,它做得很好。

标签: powershell encoding utf-8


【解决方案1】:

如果文件应该是 UTF8,为什么不尝试读取它以解码 UTF8:

Get-Content -Path test.txt -Encoding UTF8

【讨论】:

  • 因为按照官方文档,这个参数根本就不存在?我怎么会知道呢?我试试看。
  • 对不起,5 年后我不知道了。好久没怎么用PS了。
  • 参数已经存在since at least PowerShell 3.0
【解决方案2】:

真的,JPBlanc 是对的。如果您希望将其读取为 UTF8,请指定读取文件的时间。

附带说明,您在此处丢失了 [String]+[String] 内容的格式。更不用说你的正则表达式匹配不起作用。查看正则表达式搜索更改,对 $newMsgs 所做的更改,以及我将您的数据输出到文件的方式。

# Read data if exists
$data = ""
$startRev = 1;
if (Test-Path test.txt)
{
    $data = Get-Content -Path test.txt #-Encoding UTF8
    if($data -match "\br([0-9]+)\b"){
        $startRev = [int]([regex]::Match($data,"\br([0-9]+)\b")).groups[1].value + 1
    }
}
Write-Host Next revision is $startRev

# Define example data to add
$startRev = $startRev + 10
$newMsgs = @"
2014-04-01 - r$startRev`r`n`r`n
    Line 1`r`n
    Line 2`r`n`r`n
"@

# Write new data back
$newmsgs,$data | Out-File test.txt -Encoding UTF8

【讨论】:

  • 改进了它。正则表达式本身很好,只是不是我如何使用它。我在其他地方发现......没有复制正则表达式字符串的方法吗?另外,最后一个命令中的逗号有什么作用?我最初看到最后添加了许多额外的新行。
  • 找到了,一定是数组。不幸的是,第一次运行的空 $data 会导致额外的行。 – 为什么两个字符串的 + 运算符会改变它们的实际内容?在任何编程语言中这对我来说都是新的。
  • 好吧,这是 Get-Content 的错。它给了我一个行数组,而不是一个多行字符串。这会导致各种混乱。我已经切换到[System.IO.File]::ReadAllText()[System.IO.File]::WriteAllText(),现在我得到了更可预测的结果。
  • Get-Content -raw 为您提供您正在寻找的单个多行字符串。
【解决方案3】:

Get-Content 似乎根本无法处理没有 BOM 的 UTF 文件(如果您省略编码标志)。 System.IO.File.ReadLines 似乎是另一种选择,示例:

PS C:\temp\powershellutf8> $a = Get-Content .\utf8wobom.txt
PS C:\temp\powershellutf8> $b = Get-Content .\utf8wbom.txt
PS C:\temp\powershellutf8> $a2 = Get-Content .\utf8wbom.txt -Encoding UTF8
PS C:\temp\powershellutf8> $a
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ  <== This doesnt seem to be right at all
PS C:\temp\powershellutf8> $b
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ
PS C:\temp\powershellutf8> $a2
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ
PS C:\temp\powershellutf8>
PS C:\temp\powershellutf8> $c = [IO.File]::ReadLines('.\utf8wbom.txt');
PS C:\temp\powershellutf8> $c
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ
PS C:\temp\powershellutf8> $d = [IO.File]::ReadLines('.\utf8wobom.txt');
PS C:\temp\powershellutf8> $d
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ <== Works!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-04
    • 2012-01-05
    • 2016-08-14
    相关资源
    最近更新 更多