Note:
The following contains general information that in a normally functioning PowerShell environment would explain the OP's symptom. That the solution doesn't work in the OP's case is owed to machine-specific causes that are unknown at this point.
This answer is about sending BOM-less UTF-8 to an external program; if you're looking to make your PowerShell console windows use UTF-8 in all respects, see this answer.
确保您的 Java 程序接收到 UTF-8 编码的输入无物料清单, 你必须设置$OutputEncoding
to a System.Text.UTF8Encoding这样做的实例not发出 BOM:
# Assigns UTF-8 encoding *without a BOM*.
# PowerShell uses this encoding to encode data piped to external programs.
# $OutputEncoding defaults to ASCII(!) in Windows PowerShell, and more sensibly
# to BOM-*less* UTF-8 in PowerShell [Core] v6+
$OutputEncoding = [Text.UTF8Encoding]::new($false)
Caveats:
-
不要使用看似等效的New-Object Text.Utf8Encoding $false
,因为,由于中描述的错误GitHub 问题 #5763,如果你分配给$OutpuEncoding
在非全局范围内,例如在script。在 PowerShell v4 及更低版本中,使用
(New-Object Text.Utf8Encoding $false).psobject.BaseObject
作为解决方法。
-
Windows 10 版本 1903 及更高版本让你将 BOM-less UTF-8 设置为系统范围默认值编码(尽管请注意,该功能仍然被分类为beta自版本 20H2 起) - 请参阅这个答案; [PowerShell 7.1 中已修复] 在 PowerShell [核心] v7.0 及更高版本中, 启用此功能后,上述技术是not有效,由于假定的 .NET Corebug导致 UTF-8 BOMalways无论您设置什么编码,都会被发出$OutputEncoding
到(该错误可能与GitHub 问题 #28929); 唯一的解决方案是关闭该功能off,如图所示imgx64 的回答.
相比之下,如果您使用[Text.Encoding]::Utf8
,你会得到一个System.Text.Encoding.UTF8实例with BOM- 我怀疑你的情况就是这样。
请注意,此问题与任何源编码无关file阅读者Get-Content
, 因为通过 PowerShell 管道发送的绝不是流原始字节, but .NET 对象,在这种情况下Get-Content
意味着.NETstrings已发送 (System.String,内部是 UTF-16 代码单元的序列)。
因为你正在通过管道传输到外部程序(在您的情况下是一个 Java 应用程序),PowerShell 对发送给它的(按需字符串化)对象进行字符编码偏好变量$OutputEncoding,结果编码就是外部程序接收的内容。
也许令人惊讶的是,尽管 BOM 通常只使用in files, PowerShell 尊重分配给的编码的 BOM 设置$OutputEncoding
also 在管线中,将其添加到发送的第一行(仅)。
请参阅底部部分这个答案有关 PowerShell 如何处理外部程序的管道输入和输出的更多信息,包括如何it is [Console]::OutputEncoding
当 PowerShell 解释收到的数据时这很重要from外部程序.
要使用示例程序说明差异(请注意如何使用 PowerShell 字符串文字作为输入就足够了;无需从文件中读取):
# Note the EF BB BF sequence representing the UTF-8 BOM.
# Enclosure in & { ... } ensures that a local, temporary copy of $OutputEncoding
# is used.
PS> & { $OutputEncoding = [Text.Encoding]::Utf8; 'hö' | java Hex }
EF BB BF 68 C3 B6 0D 0A
# Note the absence of EF BB BF, due to using a BOM-less
# UTF-8 encoding.
PS> & { $OutputEncoding = [Text.Utf8Encoding]::new($false); 'hö' | java Hex }
68 C3 B6 0D 0A
In Windows PowerShell, where $OutputEncoding
默认为 ASCII(!),默认情况下您会看到以下内容:
# The default of ASCII(!) results in *lossy* encoding in Windows PowerShell.
PS> 'hö' | java Hex
68 3F 0D 0A
注意3F
代表字面意思?
字符,即非 ASCII 字符ö
字符也被音译,因为它没有 ASCII 表示;换句话说:信息丢失.
PowerShell [核心] v6+现在明智地默认为无 BOM UTF-8,因此默认行为符合预期。
虽然 BOM-less UTF-8 是 PowerShell [Core] 的持续的默认值,也适用于读取和写入文件的 cmdletWindows [Console]::OutputEncoding
从 v7.0 开始,默认情况下仍然反映活动的 OEM 代码页,因此要正确捕获来自 UTF-8 发射外部程序的输出,必须将其设置为[Text.UTF8Encoding]::new($false)
以及 - 参见GitHub 问题 #7233.