【问题标题】:How to create System.IO.StreamWriter with Encoding in Powershell?如何在 Powershell 中使用编码创建 System.IO.StreamWriter?
【发布时间】:2018-05-31 15:33:02
【问题描述】:

我正在尝试在 PowerShell 中使用 UTF8 编码创建 StreamWriter 实例。

$f = New-Object System.IO.StreamWriter "a.txt", $false, [System.Text.Encoding]::UTF8

这会引发错误: 新对象:找不到“StreamWriter”的重载和参数计数:“3”。

我正在尝试调用此构造函数: https://msdn.microsoft.com/en-us/library/f5f5x7kt(v=vs.110).aspx

【问题讨论】:

  • 您确定您安装了正确的 .Net?显然,构造函数是在 .Net 3.0 中引入的。
  • @DanRayson - 是的。我有最新的 .NET 和 C# 应用程序,它工作得很好。
  • @DanRayson - 当我检查时,$false 是布尔类型。
  • @DanRayson $false 是一个 automatic variable 并且是只读的,包含布尔值 false。
  • 如果您使用的是 powershell 5,请使用构造函数语法:$f = [IO.StreamWriter]::new('a.txt', $false, [Text.Encoding]::UTF8)

标签: .net powershell syntax constructor


【解决方案1】:

不过,我还是想知道我原来的语法有什么问题。

您的原始语法(基本正确)使用argument mode,其中的参数,粗略地说,评估如下:

  • 不以$、( 或@ 开头的参数被视为字符串,即使没有被引用;值得注意的是,[ 不在这些特殊字符中。

因此,[System.Text.Encoding]::UTF8 被解释为 字符串文字,而不是返回 System.Text.Encoding 实例的表达式,并且没有第三个参数的 System.IO.StreamWriter 构造函数是一个字符串可以找到。

  • 不幸的是,错误消息只提到了参数的计数,而没有指出不正确的类型可能是原因;这是一个已知问题 - 请参阅 this GitHub issue。

正如PetSerAl 的评论中提到的,正确的解决方案是将[System.Text.Encoding]::UTF8 包含在(...) 中,以强制其以表达式 模式进行评估 ,它会产生所需的结果。

请注意,上面还暗示a.txt 周围的"..."(双引号)不是必需的(但不会造成伤害),因此我们得到:

注意:为简洁起见,我在以下示例命令的完整类型中省略了初始 System. 组件;例如,IO.StreamWriter 指的是 System.IO.StreamWriter。在大多数情况下,在 PowerShell 中指定 System. 部分是可选。

$f = New-Object IO.StreamWriter a.txt, $false, ([Text.Encoding]::UTF8)

请注意,是各个构造函数参数之间的, 导致它们作为数组 - 即单个参数 - 传递给New-Object,它(位置)绑定到数组类型的-ArgumentList (-Args) 参数。
顺便说一句:将单个参数按位置传递给 separate 参数更为常见,并且需要 空格 来分隔它们;例如,Select-String foo t.txt 被解析为
Select-String -Pattern foo -Path t.txt。


您自己的答案(已删除)使用伪方法语法,这是最好避免并且只有发生工作:

# AVOID: pseudo method syntax.
$f = New-Object IO.StreamWriter("a.txt", $false, [Text.Encoding]::UTF8)

尽管这个看起来像一个方法调用(构造函数调用),但它不是,实际上解析如下:

$f = New-Object IO.StreamWriter -ArgumentList ("a.txt", $false, [Text.Encoding]::UTF8)

也就是说,您已将原始参数数组包含在(...) 中,这会导致其元素以表达式 模式进行解析,包括[Text.Encoding]::UTF8,其中正好解决了你的问题。

请注意 - 与参数模式不同 - 字符串 a.txt 确实 必须在表达式模式中包含在 "..."(或 '...')中。

顺便说一句:

  • Set-StrictMode -Version 2 或更高版本,除其他外,防止使用伪方法语法,但仅 (a) 两个或更多参数和 (b) 仅当参数列表 ((...)) 遵循 命令名称(而不是 参数,如 New-Object 的情况),并且 ( c) 仅当命令名称和开头的( 之间没有空格;例如:
    & { Set-Strictmode -version 2; foo('a', 'b') }

请注意,PSv5+ 确实提供了一种基于方法的方式来构造对象,通过静态new()方法 strong> 暴露类型信息对象,在这种情况下所有参数都以表达式模式解析:

# PowerShell version 5 and above; you can use the ::new() method on types.
$f = [IO.StreamWriter]::new("a.txt", $false, [Text.Encoding]::UTF8)

关于何时需要[System.Text.Encoding]::UTF8 的说明:

与 Window PowerShell 不同,.NET 默认为 UTF-8(PowerShell [Core] (v6+) 现在也是如此)。

  • 当您读取数据时,您通常不需要显式地请求 UTF-8 编码。

  • 当您写入数据时,传递 [System.Text.Encoding]::UTF8 会生成一个带有 BOM 的 UTF-8 文件,而依赖默认 UTF-8 编码创建一个文件没有 BOM(这对于跨平台互操作性更好);要明确请求无 BOM 编码,请使用 [System.Text.Utf8Encoding]::new()。

【讨论】:

  • 感谢您对 BOM 的评论。这正是我们遇到的问题。
猜你喜欢
  • 2012-05-02
  • 1970-01-01
  • 2020-01-22
  • 1970-01-01
  • 2020-01-30
  • 1970-01-01
  • 2021-11-14
  • 2012-09-29
  • 1970-01-01
相关资源
最近更新 更多