How to create System.IO.StreamWriter with Encoding in Powershell?

丶灬走出姿态 提交于 2021-01-24 11:59:29

问题


I'm trying to create instance of StreamWriter with UTF8 encoding in PowerShell.

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

This throws error: New-Object : Cannot find an overload for "StreamWriter" and the argument count: "3".

I'm trying to invoke this constructor: https://msdn.microsoft.com/en-us/library/f5f5x7kt(v=vs.110).aspx


回答1:


Still, I would like to know what is wrong with my original syntax.

Your original syntax (fundamentally correctly) uses argument mode, in which arguments are, loosely speaking, evaluated as follows:

  • An argument that doesn't start with either $, (, or @ is treated as a string, even if not quoted; notably, [ is not among these special characters.

Therefore, [System.Text.Encoding]::UTF8 is interpreted as a string literal rather than as an expression that returns an System.Text.Encoding instance, and no System.IO.StreamWriter constructor whose 3rd argument is a string can be found.

  • Unfortunately, the error message only mentions the count of arguments, without indicating that an incorrect type might be the cause; this is a known problem - see this GitHub issue.

The correct solution, as mentioned in a comment by PetSerAl, is to enclose [System.Text.Encoding]::UTF8 in (...) so as to force its evaluation in expression mode, where it yields the desired result.

Note that the above also implies that the "..." (double quotes) around a.txt aren't necessary (but do no harm), so we get:

Note: For brevity, I've omitted the initial System. components from the full types in the following sample commands; e.g., IO.StreamWriter refers to System.IO.StreamWriter. Specifying the System. part is optional in PowerShell in most contexts.

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

Note that it is the , between the individual constructor arguments that causes them to be passed as an array - i.e., a single argument - to New-Object, where it is (positionally) bound to the array-typed -ArgumentList (-Args) parameter.
As an aside: passing individual arguments positionally to separate parameters is more common, and requires spaces to separate them; e.g., Select-String foo t.txt is parsed as
Select-String -Pattern foo -Path t.txt.


Your own answer (since deleted) uses pseudo method syntax that is best avoided and only happens to work:

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

Even though this looks like a method call (constructor call), it isn't, and is actually parsed as follows:

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

That is, you've enclosed the original argument array in (...), which causes its elements to be parsed in expression mode, including [Text.Encoding]::UTF8, which happened to solve your problem.

Note that - unlike in argument mode - string a.txt does have to be enclosed in "..." (or '...') in expression mode.


Note that PSv5+ does offer a method-based way to construct objects, via the static new() method exposed on type-information objects, in which case all arguments are parsed in expression mode:

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

A note on when [System.Text.Encoding]::UTF8 is needed:

Unlike Window PowerShell, .NET defaults to UTF-8 (which PowerShell [Core] (v6+) now does too).

  • When you read data, you therefore normally don't need to request UTF-8 encoding explicitly.

  • When you write data, passing [System.Text.Encoding]::UTF8 results in a UTF-8 file with a BOM, whereas relying on the default UTF-8 encoding creates a file without a BOM (which is better for cross-platform interoperabiliy); to request a BOM-less encoding explicitly, use [System.Text.Utf8Encoding]::new().



来源:https://stackoverflow.com/questions/50627945/how-to-create-system-io-streamwriter-with-encoding-in-powershell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!