优化文件内容的循环
Optimise looping through file contents
我有两个文件,file1
和 file2
。我需要检查 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()
}
}
我有两个文件,file1
和 file2
。我需要检查 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()
}
}