为什么我的搜索功能在包含大量文件的文件夹上非常慢?

问题描述 投票:0回答:1

我正在尝试在区域(这是一个文件夹)内使用此逻辑搜索文件并显示它们。问题是,当文件很多(例如 200k)时,搜索需要大约 10 分钟,而在文件不多的文件夹中,搜索速度非常快。加快搜索速度的最佳方法是什么?我也尝试过使用运行空间,但没有成功,搜索时间根本没有改变。

我正在使用 Powershell 版本 5.1.22621.4249

$buttonSearch.Add_Click({
    $region = $comboBoxRegion.Text
    $payIDRange = $textBoxPayID.Text
    $checkNumRange = $textBoxCheckNum.Text
    $checkDateRange = $textBoxCheckDate.Text

    if ([string]::IsNullOrWhiteSpace($global:selectedFolder)) {
        [System.Windows.Forms.MessageBox]::Show("Please choose a folder before searching.")
        return
    }

    if ([string]::IsNullOrWhiteSpace($region)) {
        $dataGridView.Rows.Clear()
        [System.Windows.Forms.MessageBox]::Show("Please select a region.")
        return
    }

    if ([string]::IsNullOrWhiteSpace($payIDRange) -or $payIDRange -notmatch "^\d+-\d+$") {
        $dataGridView.Rows.Clear()
        [System.Windows.Forms.MessageBox]::Show("Invalid Pay ID range.")
        return
    }

    $global:totalResults = New-Object System.Collections.Generic.List[object]

    $payIDStart, $payIDEnd = $payIDRange -split "-", 2
    $payIDStart = [int]$payIDStart
    $payIDEnd = [int]$payIDEnd

    $allFiles = Get-ChildItem -Path "$global:selectedFolder\$region" -File 

    foreach ($file in $allFiles) {
        $fileInfo = Convert-FileName -fileName $file.Name
        if ($fileInfo -ne $null) {
            $extractedPayerID = [int]$fileInfo.PayerID
            $payIDValid = $extractedPayerID -ge $payIDStart -and $extractedPayerID -le $payIDEnd

            $checkNumValid = $true
            if ($checkNumRange -ne "") {
                $checkNumStart, $checkNumEnd = $checkNumRange -split "-", 2
                $checkNumValid = $fileInfo.CheckNum -ge [int]$checkNumStart -and $fileInfo.CheckNum -le [int]$checkNumEnd
            }

            $checkDateValid = $true
            if ($checkDateRange -ne "") {
                $startDate, $endDate = $checkDateRange -split " - ", 2
                $startDate = [datetime]::ParseExact($startDate.Trim(), "yyyy-MM-dd", $null)
                $endDate = [datetime]::ParseExact($endDate.Trim(), "yyyy-MM-dd", $null)
                $checkDateValid = $fileInfo.CheckDate -ge $startDate -and $fileInfo.CheckDate -le $endDate
            }

            if ($payIDValid -and $checkNumValid -and $checkDateValid) {
                $resultObject = New-Object -TypeName PSObject -Property @{
                    Name = $file.Name
                    Path = $file.FullName
                }
                $global:totalResults.Add($resultObject)
            }
        }
    }

    if ($global:totalResults.Count -eq 0) {
        $dataGridView.Rows.Clear()
        [System.Windows.Forms.MessageBox]::Show("No results found.")
        return
    }

    $global:currentPage = 0
    Show-Results
})

我尝试添加运行空间来执行更快的搜索,但没有成功。

$buttonSearch.Add_Click({
    $region = $comboBoxRegion.Text
    $payIDRange = $textBoxPayID.Text
    $checkNumRange = $textBoxCheckNum.Text
    $checkDateRange = $textBoxCheckDate.Text

    if ($global:selectedFolder -eq "") {
        [System.Windows.Forms.MessageBox]::Show("Please choose a folder before searching.")
        return
    }

    if ($region -eq "") {
        $dataGridView.Rows.Clear()
        [System.Windows.Forms.MessageBox]::Show("Please select a region.")
        return
    }

    if ($payIDRange -eq "" -or $payIDRange -notmatch "^\d+-\d+$") {
        $dataGridView.Rows.Clear()
        [System.Windows.Forms.MessageBox]::Show("Invalid Pay ID range.")
        return
    }

    $results = Search-Files -selectedFolder $global:selectedFolder -region $region -payIDRange $payIDRange -checkNumRange $checkNumRange -checkDateRange $checkDateRange

    if ($results.Count -eq 0) {
        $dataGridView.Rows.Clear()
        [System.Windows.Forms.MessageBox]::Show("No results found.")
        return
    }

    $global:totalResults = $results

    $global:currentPage = 0
    Show-Results
})


$buttonView.Add_Click({
    $selectedFiles = $global:selectedFiles

    if ($selectedFiles.Count -eq 0) {
        [System.Windows.Forms.MessageBox]::Show("No files selected for viewing.")
        return
    }

    $viewForm = New-Object System.Windows.Forms.Form
    $viewForm.Text = "View eClaims"
    $viewForm.Size = New-Object System.Drawing.Size(800, 600)
    $viewForm.FormBorderStyle = 'FixedDialog'
    $viewForm.BackColor = [System.Drawing.Color]::FromArgb(240, 240, 240)

    $tabControl = New-Object System.Windows.Forms.TabControl
    $tabControl.Dock = [System.Windows.Forms.DockStyle]::Fill
    $tabControl.Font = New-Object System.Drawing.Font("Segoe UI", 12, [System.Drawing.FontStyle]::Regular)

    foreach ($fileName in $selectedFiles) {
        $tabPage = New-Object System.Windows.Forms.TabPage
        $tabPage.Text = $fileName
        $tabPage.BackColor = [System.Drawing.Color]::White

        $tableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
        $tableLayoutPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
        $tableLayoutPanel.ColumnCount = 1
        $tableLayoutPanel.RowCount = 2
        $tableLayoutPanel.Padding = New-Object System.Windows.Forms.Padding(10)
        $tableLayoutPanel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::AutoSize)))
        $tableLayoutPanel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100)))

        $headerLabel = New-Object System.Windows.Forms.Label
        $headerLabel.Text = "Content of " + $fileName
        $headerLabel.Font = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold)
        $headerLabel.Dock = [System.Windows.Forms.DockStyle]::Top
        $headerLabel.AutoSize = $true
        $headerLabel.ForeColor = [System.Drawing.Color]::FromArgb(60, 179, 113)

        # Create a RichTextBox to display file content
        $richTextBox = New-Object System.Windows.Forms.RichTextBox
        $richTextBox.ReadOnly = $true
        $richTextBox.Dock = [System.Windows.Forms.DockStyle]::Fill
        $richTextBox.Font = New-Object System.Drawing.Font("Courier New", 10, [System.Drawing.FontStyle]::Regular)
        $richTextBox.BackColor = [System.Drawing.Color]::White
        $richTextBox.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle

        # Load the content of the file
        $filePath = ($global:totalResults | Where-Object { $_.Name -eq $fileName }).Path
        
        if (-not [string]::IsNullOrEmpty($filePath) -and (Test-Path $filePath)) {
            $richTextBox.Text = Get-Content -Path $filePath -Raw
        } else {
            $richTextBox.Text = "File not found: $fileName"
        }

        # Add controls to the TableLayoutPanel
        $tableLayoutPanel.Controls.Add($headerLabel, 0, 0)
        $tableLayoutPanel.Controls.Add($richTextBox, 0, 1)

        $tabPage.Controls.Add($tableLayoutPanel)
        $tabControl.TabPages.Add($tabPage)
    }

    $viewForm.Controls.Add($tabControl)
    $viewForm.ShowDialog()
})
windows powershell forms
1个回答
0
投票

一般来说,为了提高性能,您应该尽量减少任何循环中的计算。 您的

foreach()
循环内有一些代码不需要:

            $startDate, $endDate = $checkDateRange -split " - ", 2
            $startDate = [datetime]::ParseExact($startDate.Trim(), "yyyy-MM-dd", $null)
            $endDate = [datetime]::ParseExact($endDate.Trim(), "yyyy-MM-dd", $null)

$startDate
$endDate
每个文件都不会更改。 在
foreach
循环之前初始化它们。

你的第二次尝试也是如此,但更糟糕。为每个匹配文件添加一个选项卡可能会导致您的 UI 消耗过多的内存和处理器时间,同时变得难以使用。我不知道运行空间是在哪里实现的,也不知道它有什么帮助。您的第一次尝试就走在正确的轨道上:收集您需要的所有文件和信息,然后呈现数据。在处理过程中构建 UI 会很慢。

您可能会选择在您希望长时间运行的代码周围放置一些 Measure-Command 块。另请参阅这篇文章,了解各种变量类型的 Powershell 性能。

优化时的经验法则:尽量让循环中执行的代码尽可能小、快,并尽量让循环执行次数尽可能少。

© www.soinside.com 2019 - 2024. All rights reserved.