【问题标题】:Extract the first 50 bytes of a file using Powershell使用 Powershell 提取文件的前 50 个字节
【发布时间】:2020-03-25 20:56:50
【问题描述】:

我正在用 powershell 编写一个脚本来从服务器中提取文件信息并将数据写入 csv 文件以供审查。 我的大部分脚本运行良好,但我最初尝试提取每个文件的第一行导致了意外结果,因为某些文件没有 /cr 并因此打印整个文件内容。

我想将每个文件的前 50 个字节提取到 csv 中,但 -TotalCount 读取第一行,我一直在读取 .NET [IO.File] 和 [System.Text.Encoding] 但找不到工作方法。

我的代码目前是:


    Select-Object FullName,Name,Directory,@{n="Owner";ex={(Get-ACL $_.Fullname).Owner}},CreationTimeUtc,LastAccessTimeUtc,LastWriteTimeUtc,@{n='Size(MB)';ex={[math]::Round($_.length/1MB, 2)}},
    @{n='MD5';ex={(Get-FileHash $_.fullname).hash}},@{n="Content(UTF8)";ex={(Get-Content $_.fullname -AsByteStream -Raw -TotalCount 50)}} |

    Export-Csv c:\temp\$fn-filelisting.csv -NoTypeInformation

似乎 PS 过去使用字节作为 -TotalCount 的选择,但后来将其更改为按行读取。

由于系统限制,必须使用 PS,所以任何想法都将不胜感激。

【问题讨论】:

  • 从网上快速搜索,它看起来像[IO.File]::OpenRead($file),然后是.ReadBytes() 方法。

标签: powershell


【解决方案1】:

这将返回一个字节数组。在 powershell 5 中,它是 -encoding byte

get-content file -AsByteStream -totalcount 50

使用 powershell 5 并获取字符串:

$a = get-content file -encoding byte -totalcount 50
-join [char[]]$a

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

【讨论】:

  • 我应该提到我使用的是 PS 5.1。使用 -encoding byte 以十进制表示形式显示前 20 个字符,每行一个(例如 60、104)。
  • -join [char[]]$a 很方便,但仅在文本为 ASCII 编码(单字节编码,字节值最多为 127,无 BOM)时才有效。
【解决方案2】:

您希望读取前 50 个字符,而不是字节。 因此,使用System.IO.StreamReader 实例,因为Get-Content 不支持读取给定数量的字符,仅支持

$charBuf = [char[]]::new(50) # buffer to read into
$textStream = [IO.StreamReader] $_.FullName # create the stream reader
$charCount = $textStream.Read($charBuf, 0, $charBuf.Length) # read into buffer
$textStream.Close() # close the stream
-join $charBuf[0..($charCount-1)] # output the chars. read as a string

至于你尝试了什么:

Get-Content $_.fullname -AsByteStream -Raw -TotalCount 50

-AsByteStream 仅在 PowerShell [Core] 6+ 中受支持,它取代了 -Encoding Byte

这构成了一个不幸的重大更改:请参阅 this GitHub issuethis comment

Windows PowerShell 中,必须使用 -Encoding Byte

-TotalCount 在与-AsByteStream/-Encoding Byte结合时仅输出指定字节数有效。

但是,参数-Raw-TotalCount互斥的

虽然 Get-Content $_.fullname -Encoding Byte -TotalCount 50 / Get-Content $_.fullname -AsByteStream -TotalCount 50 因此确实在 PowerShell [Core] / Windows PowerShell 中工作,但它一个接一个地输出字节,如果你想收集所有字节在内存中

因此,添加-ReadCount 50 以便一次读取50 个字节,并将它们作为[byte[] 数组输出

# Read 50 bytes at once and utput a [byte[]] array

# Windows PowerShell:
Get-Content $_.fullname -Encoding Byte -TotalCount 50 -ReadCount 50

# PowerShell [Core] 6+
Get-Content $_.fullname -AsByteStream -TotalCount 50 -ReadCount 50

PowerShell [Core] 7 中,提供了一种优化:-ReadCount 0 是一个快捷方式,用于请求将任何计数 -TotalCount 请求读入单个数组:

# PowerShell 7
Get-Content $_.fullname -Encoding Byte -TotalCount 50 -ReadCount 0

虽然上面是提取前 50 个字节的相当有效的方法,但将它们转换为字符

  • 比较麻烦,因为你需要知道源字符编码,并根据它将字节转换为文本。

  • 但更重要的是,如果输入文件使用 variable-length 编码,尤其是 UTF-8,如果 50 -byte 边界恰好落在组成单个字符的 多个 个字节的中间,在 UTF-8 中适用于 ASCII 范围之外的任何字符,例如 é

从 v7.0 开始,Get-Content 不提供读取指定数量的字符的方法,这就是上述解决方案中使用 .NET System.IO.StreamReader 类型的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 2020-03-09
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多