Powershell 将类的输出写入文本文件会添加空行

Powershell 将类的输出写入文本文件会添加空行,powershell,Powershell,我创建了一个类来收集脚本中的一些数据,但不确定这是否是正确的使用方法。当我将类输出到文本文件时,它每次写入该文件时都会添加2个空行。有没有办法去掉这个 [int] $numOut = 0 [int] $numIn = 0 [int] $numNone = 0 [int] $numCPE = 0 [int] $numSQR = 0 [int] $numEGX = 0 [int] $numCQA = 0 代码的各个部分都是这样做的,这些是对这些变量进行操作的唯一类型 它像这样写入文件: area

我创建了一个类来收集脚本中的一些数据,但不确定这是否是正确的使用方法。当我将类输出到文本文件时,它每次写入该文件时都会添加2个空行。有没有办法去掉这个

[int] $numOut = 0
[int] $numIn = 0
[int] $numNone = 0
[int] $numCPE = 0
[int] $numSQR = 0
[int] $numEGX = 0
[int] $numCQA = 0
代码的各个部分都是这样做的,这些是对这些变量进行操作的唯一类型


它像这样写入文件:

arealhobo 10/24/2020 19:47:24 1      0     1       1     1      0             1


arealhobo 10/24/2020 19:50:37 1      0     1       1     1      0             1


arealhobo 10/24/2020 19:53:15 1      0     1       1     1      0             1

可以先替换换行符:

(write-output $logging | Format-Table -AutoSize -HideTableHeaders | Out-string) -replace "\n","" >> $CWD\log.txt

您还可以实现一个方法来处理向文件的输出。这里有一个例子

class Logging {
    [string]$DateTime
    [string]$User
    [string]$numOut
    [string]$numIn
    [string]$numNone
    [string]$numCPE
    [string]$numSQR
    [string]$numEGX
    [string]$numCQA
    [string]$total

    Log($file){
        $this | Export-Csv -Path $file -Delimiter "`t" -Append -NoTypeInformation
    }
}

$Logging = [Logging]::new()
$Logging.DateTime = Get-Date
$Logging.User = $env:username
$logging.NumOut = $numOut
$logging.NumIn = $numIn
$logging.NumNone = $numNone
$logging.NumCPE = $numCPE
$logging.NumSQR = $numSQR
$logging.NumEGX = $numEGX
$logging.NumCQA = $numCQA
$logging.Total = $total
现在您只需调用
$logging.log(“path\to\logfile”)
指定写入位置

$Logging.log("c:\Some\Path\logging.log")

注意:下面描述的场景可能与OP不匹配。如果您在使用
>
附加到Windows PowerShell中预先存在的文件后发现文件内容按如下方式打印到控制台,则答案可能仍然很有趣;请注意额外的间距和额外的空行:


为了避免您的问题,这很可能是由于输出文件中由
>
产生的不同字符编码的意外混合造成的,您有两个选项:

  • 如果您确实知道输出文件中预先存在的内容所使用的字符编码,请通过
    -encoding
    参数使用并匹配该编码:
请注意,
/
>
实际上就像调用
Out File
/
Out File-Append
,只是您无法控制字符编码

  • 在不太可能的情况下,如果您不知道先前存在的字符编码,您可以使用自动匹配的,这与
    >
    /
    Out File-Append不同,但这需要额外的工作:

    • 需要预先进行额外调用,以提供
      >
      (和
      >
      /
      输出文件
      )隐式提供的格式;如果没有它,
      添加内容
      (和
      设置内容
      )将对输出对象应用简单的
      .ToString()
      字符串化,对于通过
      格式-*
      cmdlet输出的对象,这些对象只会产生无用的表示,即它们的类型名称(例如,
      Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
      ):
请继续阅读背景信息


假设您使用的是Windows PowerShell而不是PowerShell[Core]v6+[1]:

最有可能的原因(解释与您问题中的输出不完全匹配,但我怀疑这是一个发布工件):

  • 您有一个先前存在的带有单字节字符编码的
    log.txt
    文件[2],很可能是基于系统活动ANSI代码页的传统编码,也可能是UTF-8编码文件(有或没有BOM)

  • 当您在内容中添加
    >
    时,PowerShell盲目地将其默认字符编码用于
    /
    >
    ,在Windows PowerShell[1]中它是“Unicode”(UTF-16LE),实际上是一种双字节编码[2](但从技术上讲不是这样)这些重定向操作符是
    输出文件[-Append]
    的别名

结果是,在以后读取文件时,新添加的文本会被误解,因为UTF-16LE字符是逐字节读取的,而不是被解释为两个字节序列

由于ASCII范围内的字符有一个
NUL
字节作为其2字节表示形式中的第二个字节,读取文件字节会在每个原始字符后看到一个额外的
NUL
“`0”
)字符

在Windows[3]上,当您使用
Get content
将文件内容打印到控制台时,这有两种效果:

  • 在ASCII范围字符之间插入看似空格的字符,因此,例如,
    foo
    打印为
    fo
    ——实际上,这些是额外的
    NUL
    字符

  • 在每行之后插入一个额外的(显然)空行,这是PowerShell交替接受不同换行样式(CRLF、LF、CR)的副作用:

    • 由于额外的
      NUL
      s,原始CRLF序列(
      “`r`n”
      )被读取为
      “`r`0`n`0”
      ,这导致PowerShell将
      “`r”
      “`n”
      分别视为换行符(换行符),从而产生额外的行

    • 请注意,额外的行实际上包含一个
      NUL
      ,随后的行以
      NUL
      开头(从
      “`n”
      开始的尾随行),因此在被误解的行中,除第一行外,所有行似乎都以空格开头


[1] PowerShell[Core]v6+现在在所有cmdlet中一致默认为无BOM的UTF-8
。而
>
Out File-Append
)仍然与现有编码不匹配,UTF-8文件的流行使问题更小。有关PowerShell中字符编码的详细信息,请参阅

[2] 严格来说,and是可变长度编码,因为UTF-8中的每个字节不一定都是自己的字符(仅适用于ASCII范围内的字符),同样,某些(外来)字符需要UTF-16中的两个2字节序列。然而,可以公平地说UTF-8/UTF-16是基于单/双字节的

[3] 在类Unix平台(Linux、macOS)上,您甚至可能在打印到终端时没有注意到问题,因为他们的终端仿真器通常忽略
NUL
s,并且由于只使用LF(
“`n”
class Logging {
    [string]$DateTime
    [string]$User
    [string]$numOut
    [string]$numIn
    [string]$numNone
    [string]$numCPE
    [string]$numSQR
    [string]$numEGX
    [string]$numCQA
    [string]$total

    Log($file){
        $this | Export-Csv -Path $file -Delimiter "`t" -Append -NoTypeInformation
    }
}

$Logging = [Logging]::new()
$Logging.DateTime = Get-Date
$Logging.User = $env:username
$logging.NumOut = $numOut
$logging.NumIn = $numIn
$logging.NumNone = $numNone
$logging.NumCPE = $numCPE
$logging.NumSQR = $numSQR
$logging.NumEGX = $numEGX
$logging.NumCQA = $numCQA
$logging.Total = $total
$Logging.log("c:\Some\Path\logging.log")
# Using UTF-8 in this example.
$logging | Format-Table -AutoSize -HideTableHeaders |
  Out-File -Append -Encoding Utf8 $CWD\log.txt
# Add-Content, unlike >>, matches the character encoding of the existing file.
# Since Add-Content, unlike > / >> / Out-File, uses simple .ToString()
# stringification you first need a call to `Out-String`, which provides
# the same formatting that > / >> / Out-File implicitly does.
$logging | Format-Table -AutoSize -HideTableHeaders |
  Out-String -Stream | Add-Content $CWD\log.txt