首页 > 解决方案 > 如何在 Powershell 中使用编码创建 System.IO.StreamWriter?

问题描述

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

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

这会引发错误:New-Object:找不到“StreamWriter”的重载和参数计数:“3”。

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

标签: .netpowershellsyntaxconstructor

解决方案


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

您的原始语法(基本上正确)使用参数模式,其中参数,松散地说,评估如下:

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

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

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

正如PetSerAl的评论中提到的,正确的解决方案是封闭[System.Text.Encoding]::UTF8(...)以便在表达式模式下强制其评估,从而产生所需的结果。

请注意,上面还暗示"..."(双引号)周围a.txt不是必需的(但没有害处),所以我们得到:

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

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

请注意,导致它们作为数组(即单个参数)传递给 的,,New-Object各个构造函数参数之间的,其中它(位置上)绑定到数组类型的-ArgumentList( -Args) 参数。
顺便说一句:将单个参数按位置传递给单独的参数更常见,并且需要空格来分隔它们;例如,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()方法,在这种情况下,所有参数都以表达式模式解析:

# 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 编码。

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


推荐阅读