首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何从PowerShell中的字符串中对特定字节数进行子串?

如何从PowerShell中的字符串中对特定字节数进行子串?
EN

Stack Overflow用户
提问于 2022-06-13 15:05:12
回答 1查看 158关注 0票数 2

我有一个场景,需要获得一个嵌入在JSON响应中的安装程序,该响应是base64 64编码的。由于JSON字符串的大小相当大(180 MB),因此在使用标准PowerShell工具解码REST响应时会出现问题,因为它会导致在有限内存场景中抛出OutOfMemoryException (例如按WinRM内存配额)。

通过单个安装来提高环境中的内存配额是不可取的,而且我们也没有标准的工具来准备一个包,它的有效负载在简单的HTTP端点上不存在(我没有直接的权限来发布没有通过我们的构建系统执行的包)。在这种情况下,我的解决方案是以块的形式解码base64字符串。然而,虽然我有这个工作,但我仍然停留在这个过程的最后一点优化上。

目前,我正在使用MemoryStream从字符串中读取数据,但我需要提供一个byte[]

代码语言:javascript
运行
复制
# $Base64String is a [ref] type
$memStream = [IO.MemoryStream]::new([Text.Encoding]::UTF8.GetBytes($Base64String.Value))

这并不令人意外地导致复制整个base64 64编码字符串的byte[]表示,并且在其当前形式中,内存效率甚至低于内置工具。这里没有看到的代码一次从$memStream读取大块1024字节,解码base64字符串并使用BinaryWriter将字节写入磁盘。这一切都很好,如果速度慢的话,因为我经常强制垃圾收集。但是,我希望将这个字节计数扩展到初始的MemoryStream,并且一次只从字符串中读取n字节。我的理解是,base64字符串必须以可以被4除的字节块解码。

问题是,[string].Substring([int], [int])基于字符串长度,而不是每个字符的字节数。JSON响应可以假定为UTF-8编码,但即使在这种假设下,UTF-8字符的长度在1-4字节之间。如何(直接或间接)子字符串(直接或间接)在PowerShell中的特定字节数,以便我可以从这个子字符串而不是完整的$Base64String创建MemoryStream

我将注意到,我已经探索了[[Text.Encoding].GetBytes([string], [int], [int])重载]的用法(然而,我也面临同样的问题,因为该方法期望字符串长度为字符计数,而不是字节计数,以便从起始索引中获取byte[]

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-13 18:59:42

为了回答基本问题“如何从PowerShell中的字符串中将特定数目的字节子字符串”,我编写了以下函数:

代码语言:javascript
运行
复制
function Get-SubstringByByteCount {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory)]
    [ValidateScript({ $null -ne $_ -and $_.Value -is [string] })]
    [ref]$InputString,
    [int]$FromIndex = 0,
    [Parameter(Mandatory)]
    [int]$ByteCount,
    [ValidateScript({ [Text.Encoding]::$_ })]
    [string]$Encoding = 'UTF8'
  )
  
  [long]$byteCounter = 0
  [System.Text.StringBuilder]$sb = New-Object System.Text.StringBuilder $ByteCount

  try {
    while ( $byteCounter -lt $ByteCount -and $i -lt $InputString.Value.Length ) {
      [char]$char = $InputString.Value[$i++]
      [void]$sb.Append($char)
      $byteCounter += [Text.Encoding]::$Encoding.GetByteCount($char)
    }

    $sb.ToString()
  } finally {
    if( $sb ) {
      $sb = $null
      [System.GC]::Collect()
    }
  }
}

调用的工作方式如下:

代码语言:javascript
运行
复制
Get-SubstringByByteCount -InputString ( [ref]$someString ) -ByteCount 8

关于这一执行的一些说明:

  • 将字符串作为[ref]类型,因为最初的目标是避免在有限内存场景中复制完整字符串。这个函数可以使用[string]类型重新实现。
  • 这个函数实质上是将每个字符添加到一个StringBuilder中,直到指定的字节数被写入为止。
  • 每个字符的字节数是通过使用[Text.Encoding]::GetByteCount重载之一来确定的。可以通过参数指定编码,但编码值应该与[Text.Encoding]中可用的静态编码属性之一相匹配。默认情况下,written.
  • $sb = $null[System.GC]::Collect()用于在内存受限的环境中强制清除StringBuilder,但如果这不是concern.
  • -FromIndex-InputString中开始子字符串操作的起始位置,则可以省略。默认为从-InputString.

开始计算的0

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72605084

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档