如何通过powershell将每一行文本文件保存为数组
Posted
技术标签:
【中文标题】如何通过powershell将每一行文本文件保存为数组【英文标题】:How to save each line of text file as array through powershell 【发布时间】:2019-02-09 17:56:13 【问题描述】:如果我有一个文本文件,C:\USER\Documents\Collections\collection.txt 包含以下信息:
collectionA.json
collectionB.json
collectionC.json
collectionD.json
我想知道如何通过 Powershell 将文本文件中的每一行存储为数组的元素,例如......
array arrayFromFile = new Array;
foreach(line x in collection.txt)
arrayFromFile.Add(x);
..最终目标是:
foreach(string x in arrayFromFile)
newman run x;
对于这个看似简单的问题,我深表歉意 - 我以前从未处理过 Powershell。
【问题讨论】:
顺便说一句:您不能使用.Add()
来扩展数组,因为数组是固定大小的列表(而.Add()
方法由于实现IList
接口而存在,它会抛出异常在运行时达到这种效果)。
除此之外,您还可以使用$myArr = New-Object System.Collections.ArrayList
并使用相同的.Add
方法添加到它们是动态的。
【参考方案1】:
Get-Content
命令将文本文件中的每一行作为单独的字符串返回,因此会给您一个数组(只要您不使用-Raw
参数;这会导致所有行合并为一个单个字符串)。
[string[]]$arrayFromFile = Get-Content -Path 'C:\USER\Documents\Collections\collection.txt'
在his excellent answer 中,mklement0 提供了更多关于调用此命令时实际发生的情况的详细信息,以及如果您担心性能而不是便利性的替代方法。如果您有兴趣了解更多有关该语言的知识,而不仅仅是解决这一一次性要求,那么绝对值得一读。
【讨论】:
【参考方案2】:补充JohnLBevan's helpful answer:
Get-Content
,作为 cmdlet,将对象一个一个输出到pipeline,当它们可用时 .(请注意,即使在没有管道符号 |
的情况下调用 cmdlet 以链接多个命令时,也会涉及管道)。
在这种情况下,输出对象是输入文本文件的各个 行。
如果您收集管道的输出对象,例如通过将其分配给变量(例如$arrayFromFile
)或使用管道在(...)
的更大表达式的上下文中:
[object[]]
,
但如果只有一个输出对象,则按原样捕获该对象(没有数组包装)
但是,通常没有必要确保您始终收到 数组,因为 PowerShell 处理 标量 em>(不是集合的单个值)在许多上下文中与 arrays(集合)相同,例如在foreach
语句中或在输出要枚举到管道的值时,例如,通过ForEach-Object
cmdlet 处理;因此,无论输入文件包含多少行,以下命令都可以正常工作:
# OK - read all lines, then process them one by one in the loop.
# (No strict need to collect the Get-Content output in a variable first.)
foreach ($line in Get-Content C:\USER\Documents\Collections\collection.txt)
newman run $line
# Alternative, using the pipeline:
# Read line by line, and pass each through the pipeline, as it is being
# read, to the ForEach-Object cmdlet.
# Note the use of automatic variable $_ to refer to the line at hand.
Get-Content C:\USER\Documents\Collections\collection.txt |
ForEach-Object newman run $_
为了确保命令的输出始终是一个数组,PowerShell 提供了@(...)
, the array-subexpression operator,它甚至将单个对象的输出包装在一个数组中。
因此,PowerShell 惯用的解决方案是:
$arrayFromFile = @(Get-Content C:\USER\Documents\Collections\collection.txt)
TheMadTechnician 指出您还可以使用[array]
强制转换/类型约束管道输出作为@(...)
的替代方案,@(...)
也会创建[object[]]
数组:
# Equivalent of the command above that additionally locks in the variable date type.
[array] $arrayFromFile = Get-Content C:\USER\Documents\Collections\collection.txt
通过使用[array] $arrayFromFile = ...
而不是$arrayFromFile = [array] (...)
,变量$arrayFromFile
变为类型受限,这意味着它的数据类型被锁定(而默认情况下,PowerShell 允许您更改类型任何时候的变量)。
[array]
是 John 的答案 [string[]]
中使用的 type-specific 强制转换的与命令无关的替代方案;您可以使用后者来强制在数组元素中使用统一类型,但这在 PowerShell[1] 中通常不是必需的
.
常规 PowerShell 数组的类型为 [object[]]
,它允许混合不同类型的元素,但任何给定元素仍然具有特定类型;例如,即使在上面的命令之后$arrayFromFile
的类型是[object[]]
,$arrayFromFile[0]
的类型,即第一个元素,例如,是[string]
(假设文件包含至少 1 行;验证$arrayFromFile[0].GetType().Name
的类型)。
更快的选择:直接使用 .NET 框架
Cmdlet 和管道提供了高级的、潜在的内存限制功能,这些功能具有表现力和方便性,但它们可能缓慢。
当性能很重要时,直接使用 .NET 框架类型是必要的,例如 [System.IO.File]
在这种情况下。
$arrayFromFile = [IO.File]::ReadAllLines('C:\USER\Documents\Collections\collection.txt')
注意System.
前缀是如何从类型名称中省略的。
正如 John 的回答,这将返回一个 [string[]]
数组。
注意事项:
小心相对路径,因为.NET通常有一个不同的当前目录而不是PowerShell;为了解决这个问题,总是通过绝对路径,在最简单的情况下使用"$PWD/collection.txt"
,最稳健使用"$((Get-Location -PSProvider FileSystem).ProviderPath)/collection.txt"
.NET 的默认编码为 UTF-8,而 Windows PowerShell 默认为“ANSI”编码,即系统区域设置的旧代码页;相比之下,PowerShell Core (v6+) 也默认为 UTF-8。使用Get-Encoding
的-Encoding
参数或接受编码实例的.ReadAllLines()
重载显式指定输入文件的字符编码。
[1] 通常,例如,PowerShell 的隐式运行时类型转换无法提供与 C# 相同的类型安全性。例如,[string[]] $a = 'one', 'two'; $a[0] = 42
不会 导致错误:PowerShell 只是悄悄地将 [int]
42
转换为字符串。
【讨论】:
非常感谢您的出色回答。我已经测试了 .NET 方法,它的速度快了 10 倍以上。 113k 行耗时:0.0933256 秒,使用 Get-Content 耗时:1.1153968 秒。【参考方案3】:$array = Get-Content -Path @("C:\tmp\sample.txt")
foreach($item in $array)
write-host $item
【讨论】:
展示一个完整示例的好主意。请注意,@(...)
不需要围绕 -Path
参数,-Path C:\tmp\sample.txt
可以。 PowerShell 中的数组值参数也总是接受一个标量值(即使有多个值,-Path sample1.txt, sample2.txt
也可以)。以上是关于如何通过powershell将每一行文本文件保存为数组的主要内容,如果未能解决你的问题,请参考以下文章
Javascript / Jquery识别文本文档中的每一行[重复]