用以下解决方案补充Mathias R. Jessen 的有用答案:
- 效率更高。
- 确保输入文件被读取为 UTF-8,即使它们没有(伪)BOM(字节顺序标记)。
- 通过编写没有伪 BOM的 UTF-8 编码输出文件,完全避免了“奇怪的字符”问题。
# Explicitly read the input files as UTF-8, as a whole.
$content = get-content -raw -encoding utf8 test.html
$template = get-content -raw -encoding utf8 template.html
# Write to output file using UTF-8 encoding *without a BOM*.
[IO.File]::WriteAllText(
"$PWD/out.html",
$ExecutionContext.InvokeCommand.ExpandString($template)
)
get-content -raw
(PSv3+) 将文件作为一个整体读入单个字符串(而不是字符串数组,逐行),虽然更占用内存,但速度更快。对于 HTML 文件,内存使用不应该成为问题。
- 完整读取文件的另一个优点是,如果模板包含多行子表达式 (
$(...)
),则扩展仍然可以正常工作。
get-content -encoding utf8
确保输入文件被解释为使用字符编码 UTF-8,这在当今的网络世界中很常见。
- 这是至关重要的,因为UTF-8 编码的 HTML 文件通常没有PowerShell 需要的 3 字节伪 BOM,以便正确地将文件识别为 UTF-8 编码(见下文)。
一次$ExecutionContext.InvokeCommand.ExpandString()
调用就足以执行模板扩展。
Out-File -Encoding utf8
总是会创建一个带有伪 BOM 的文件,这是不受欢迎的。
取而代之的[IO.File]::WriteAllText()
是,利用 .NET Framework默认创建没有BOM的 UTF-8 编码文件这一事实。
- 注意
$PWD/
before的使用out.html
,这是确保文件写入PowerShell的当前位置(目录)所必需的;不幸的是,.NET Framework 认为当前目录与 PowerShell不同步。
最后,强制性安全警告:仅在您信任的输入上使用此扩展技术,因为可能会执行任意嵌入式命令。
可选的背景信息
PowerShell 的Out-File
,>
并默认>>
使用带有BOM(字节顺序标记)的UTF-16 LE 字符编码(如前所述,“奇怪的字符”)。
虽然Out-File -Encoding utf8
允许创建 UTF-8 输出文件,但
PowerShell总是在输出文件前添加一个 3 字节的伪 BOM,一些实用程序,尤其是那些具有 Unix 传统的实用程序存在问题 - 所以你仍然会得到“奇怪的字符”(尽管不同的)。
如果您想要一种更类似于 PowerShell 的方式来创建无 BOM 的 UTF-8 文件,请参阅我的这个答案,它定义了一个Out-FileUtf8NoBom
函数,该函数以其他方式模拟Out-File
.
相反,在读取文件时,您必须使用Get-Content -Encoding utf8
确保无 BOM 的 UTF-8 文件被识别为此类文件。
在没有 UTF-8 伪 BOM 的情况下,Get-Content
假定文件使用系统的旧代码页指定的单字节扩展 ASCII 编码(例如,英语系统上的Windows-1252Default
,PowerShell 调用的编码) .
请注意,虽然仅 Windows 的编辑器(例如记事本)使用伪 BOM 创建 UTF-8 文件(如果您明确选择保存为 UTF-8;默认为旧代码页编码“ANSI”),但越来越流行的跨平台编辑器例如Visual Studio Code、Atom和Sublime Text在创建文件时默认不使用伪 BOM。