这似乎非常简单,但我缺少一些东西。我只需要向array [0],array [1]等添加一个数组。 我正在获取vcard文件,并尝试读取一个vcard的所有行,并将它们放入数组中,然后将该数组放入数组中,以便array [0]将为vcard 1,array [1]将为下一个,依此类推
$c = Get-Content -Path C:\temp\Contacts_Backup.vcf
$counter=0
$contact=@()
$allcontacts=@()
Foreach ($line in $c){
$contact += $line
if ($line -eq 'END:VCARD'){
$allcontacts[$counter++] = $contact
$contact=@()
}
}
结果: 无法索引到System.String类型的对象。
答案 0 :(得分:1)
tl;博士:
您不能通过分配不存在的索引 来“增长”数组;如果您以@()
开始-一个空数组-您必须使用+=
来“追加”元素(数组是固定大小的集合,所以真正发生的是必须每次分配一个 new 数组,该数组包含旧元素,后跟新元素)。
因此,在循环中使用+=
效率低,并且有两种替代方法:
使用.NET可扩展列表类型可以更有效地构建类似数组的集合。
最好-因为它既方便又快捷-l 让 PowerShell 为您创建数组,只需通过捕获foreach
循环中的输出即可变量
($array = @(foreach (...) { ... })
)
下面的详细信息。
您的代码确实存在问题,尽管它产生的症状与您的问题当前所陈述的有所不同;用一个简化的例子:
PS> $allcontacts=@(); $allcontacts[0] = 'one', 'two'
Index was outside the bounds of the array. # ERROR
...
也就是说,@()
创建一个 empty 数组,您不能通过访问不存在的 index 隐式地“扩展”该数组。
像使用+=
数组那样使用$contacts
确实可以:
$allcontacts=@(); $allcontacts += , ('one', 'two')
请注意使用数组构造运算符,
以确保将RHS操作数作为一个整体 添加为一个新元素;没有它,将添加多个元素,每个元素一个。
但是,虽然可以使用+=
“扩展”数组,但实际上您每次都在幕后创建一个 new 数组,因为根据定义,数组是固定的 -size 集合。
对于较大的集合,这可能会成为性能问题,最好使用 list 数据类型,例如[System.Collections.Generic.List[object]]
[1] :
$allcontacts = New-Object Collections.Generic.List[object]
$allcontacts.Add(('one', 'two'))
请注意,需要在(...)
中将数组添加为单个列表元素,以便.Add()
方法将其识别为单个参数。
退后一步:您可以让 PowerShell 只需捕获整个{{1}的输出,就可以收集整个$contact
数组中的$allcontacts
个子数组}命令:
foreach
$c = Get-Content -Path C:\temp\Contacts_Backup.vcf
$contact=@()
$allcontacts=@()
$allcontacts = @(foreach ($line in $c){
$contact += $line
if ($line -eq 'END:VCARD'){
# Output the $contact array as a *single* object,
# using ",", the array-construction operator
, $contact
$contact=@()
}
})
最终将成为常规的PowerShell数组,键入$allcontacts
。
仅当您需要确保[object[]]
是一个数组时,才需要使用array-subexpression运算符(@(...)
),即使$allcontacts
文件仅包含一个联系人定义。
[1]一种非通用的替代方法是*.vcf
,但缺点是其[System.Collections.ArrayList]
方法返回一个值,需要您禁止该值与.Add()
一起使用,以免污染PowerShell的输出流。
答案 1 :(得分:1)
这应该完全满足您的要求:
Add-Type -AssemblyName System.Collections
[System.Collections.Generic.List[object]]$allContacts = @()
[System.Collections.Generic.List[string]]$contact = @()
$filePath = 'C:\temp\Contacts_Backup.vcf'
$endMarker = 'END:VCARD'
foreach($line in [System.IO.File]::ReadLines($filePath))
{
if( $line -eq $endMarker ) {
$allContacts.Add( $contact.ToArray() )
$contact.Clear()
}
else {
$contact.Add( $line )
}
}
# Ready. Show result.
foreach( $vcf in $allContacts ) {
"Contact: "
$vcf
}