比较大文件

时间:2017-08-23 13:20:28

标签: powershell csv scripting

我有一个脚本,用于检查文件2中是否存在文件1中的URL,如果不存在,则将其写入输出文件。它工作正常,这是:

Write-Host "Script output will have unique items from file 1"
$FirstPath = Read-Host -Prompt "Input file location of first .csv file"
$SecondPath = Read-Host -Prompt "Input file location of second .csv file"

Write-Host "Importing CSV files..."
$FirstFile = Import-Csv $FirstPath -Delimiter ';' |
             Select-Object -ExpandProperty Url
$SecondFile = Import-Csv $SecondPath -Delimiter ';' |
              Select-Object -ExpandProperty ITEM_TARGET_URI

Write-Host "Comparing files..."
Compare-Object -ReferenceObject $FirstFile -DifferenceObject $SecondFile -PassThru |
    Where-Object { $_.SideIndicator -eq "<=" } |
    Out-File -Encoding Utf8 .\result.txt

Write-Host "Done, press any key to continue..."
$x = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

我的问题是,当处理大型CSV文件(例如一个有4 000 000条记录)时,脚本工作了一整晚,但仍然没有完成。我也无法看到是否有任何进展。我想让它更快地工作,或者至少有一些关于工作进展的信息。我已经阅读了有关进度条等的信息。但由于它仅在一行中进行比较而不是循环,因此无法工作。

我可以在脚本中更改哪些内容以使其更快地运行和/或能够看到进度?

编辑:问题与网络模式不同,我主要专注于处理大文件和提高脚本速度。解决方案在那里没有回答这个问题。

2 个答案:

答案 0 :(得分:1)

由于您显然只想要第一个文件中不存在于第二个文件中的网址,因此您可能需要尝试以下内容:

$ref = Import-Csv $SecondPath -Delimiter ';' |
       Select-Object -Expand ITEM_TARGET_URI

Import-Csv $FirstPath -Delimiter ';' |
    Select-Object -Expand Url |
    Where-Object { $ref -notcontains $_ } |
    Out-File -Encoding UTF8 .\result.txt

这假设Compare-Object是您的实际瓶颈。您是否验证了(通过计算import语句和compare语句)?

如果比较操作不是主要瓶颈(例如,数据导入需要相同的长时间或更长时间),您可能希望用{/ p>之类的内容替换Import-Csv

$ref = Get-Content $SecondPath |
       Select-Object -Skip 1 |
       ForEach-Object { $_.Split(';')[5] }

或者像这样:

$reader = New-Object IO.StreamReader $SecondPath

[void]$reader.ReadLine()  # skip header line
$ref = while ($reader.Peek() -gt 0) {
    $reader.ReadLine().Split(';')[5]
}

$reader.Close(); $reader.Dispose()

5替换为要提取其值的列的索引。

附录:您应该能够通过使用哈希表查找而不是-notcontains来大大加快处理速度。

$ref = @{}
Import-Csv $SecondPath -Delimiter ';' | ForEach-Object {
    $ref[$_.ITEM_TARGET_URI] = $true
}

Import-Csv $FirstPath -Delimiter ';' |
    Where-Object { -not $ref.ContainsKey($_.Url) } |
    Select-Object -Expand Url |
    Out-File -Encoding UTF8 .\result.txt

答案 1 :(得分:0)

$FirstFile | Where {$SecondFile -NotContains $_}