如何通过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)或使用管道在(...) 的更大表达式的上下文中:

PowerShell 在一个自动创建的数组中捕获多个输出对象,类型为[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将每一行文本文件保存为数组的主要内容,如果未能解决你的问题,请参考以下文章

c#读取文本文档实践3-写入到文本本文档

Javascript / Jquery识别文本文档中的每一行[重复]

如何将文件(IN C)中的每一行保存在变量中? :)

更新tkinter标签以在我的python GUI上一次显示一行文本文件

网络-Cisco考试

如何对大文本文件运行字典搜索?