优化文件内容的循环

Optimise looping through file contents

我有两个文件,file1file2。我需要检查 file1 中的所有内容是否都存在于 file2 中。 file1 的内容如下:

ABC1234
BFD7890

file2的内容如下:

ABC1234_20180902_XYZ
BFD7890_20110890_123

它们不会有任何特定的顺序,并且不能用分隔符分割,因为它们在不同的行中是不同的。我唯一需要确认的是 file1 的字符串是否出现在 file2 的某些部分。不会出现两次相同的模式。

两个文件都包含超过 20000 行。

这是我目前拥有的:

$filesfromDB   = gc file1.txt
$filesfromSFTP = gc file2.txt
foreach ($f in $filesfromDB) {
    $FilePresentStatus = $filesfromSFTP | Select-String -Quiet -Pattern $f
    if ($FilePresentStatus -ne $true) {
        $MissingFiles += $f
    }
}

如果文件很小,这很好用,但是当我 运行 在产品中使用它时,它真的很慢。完成这个循环大约需要 4 个小时。如何优化这段脚本?

我认为你的问题出在 += 运算符上,试试这个 https://powershell.org/2013/09/16/powershell-performance-the-operator-and-when-to-avoid-it/

20000 不算多,但最坏的情况下你必须执行 20000x20000=400000000 次操作。关键是在每一次中尽快停止。您还可以使用更快的 [string].Contains 方法而不是基于正则表达式的 Select-String(除非使用 -SimpleMatch 开关)。

请参阅以下演示:

$db =   1000000..1020000
$sftp = (1001000..1021000 | % { "$($_)_SomeNotImportantTextHere" }) -join "`r`n"

$missingFiles = $db | where { !$sftp.Contains($_) }

每个集合包含 20000 个项目,19000 个常见项目,1000 个仅存在于 $db。它会在几秒钟内运行。

要将 $filesfromSFTP 读取为一个大字符串,请使用:

gc file2.txt -Raw

要将结果转换为单个字符串,请使用 $missingFiles -join 'separator'

使用哈希表,下面的代码在我的笔记本电脑上花费了大约 15 分钟,其中包含 2 个包含 20000 行的文件。

$filesfromDB   = gc file1.txt
$filesfromSFTP = gc file2.txt
$MissingFiles  = @()
$hashtbl       = @{}

foreach ($f in $filesfromDB) {
    $hashtbl."Line$($f.ReadCount)"=[regex]$f
}

foreach ($key in $hashtbl.Keys) {
    $FilePresentStatus = $hashtbl[$key].Matches($filesfromSFTP)
    if ($FilePresentStatus.Count -eq 0) {
        $MissingFiles += $hashtbl[$key].ToString()
    }
}