Сравнение массива в PowerShell с неэффективным каталогом файлов - PullRequest
0 голосов
/ 23 января 2019

Я не совсем новичок в PS, но я беру все это на работу без направления, что усложняет обучение, поскольку есть вещи, о которых я не знаю, которых я не знаю. При этом у меня есть полностью функционирующий сценарий, и я хотел бы получить указатели о том, как сделать это быстрее или, возможно, получить совершенно другой способ сделать это.

Проблема: У меня есть куча фотографий в папке, которые мне нужно сравнить со списком идентификаторов из таблицы SQL. Если я найду совпадение, мне нужно переместить эту фотографию в другой каталог для обработки

Я знаю, что это неэффективно, так как я вызываю каталог на каждой итерации цикла ID, но я не смог заставить его работать, если я попытался также создать массив файлов для проверки, а затем сравнить два массива.

Опять же, функциональность отличная, просто она не быстрая.

CLS

$startDate = Get-Date
$startDate

$photoSourceLocation = "C:\Temp\Photos\Aggregate" #"C:\Temp\Photos\Moved"
$photoDropLocation = "C:\Temp\Photos\Process"

$IdQuery = "SELECT ST.Id FROM SomeTable as ST"


$patients = Invoke-Sqlcmd -Query $IdQuery -ServerInstance "SQLServer" -Database "DB"
$photos = GCI $photoSourceLocation -File

$patientRaw = $patients | Measure 
$patientCount = $patientRaw.Count

#$PatientCount
$I = 1
$Out= ""

forEach ($patient in $Patients)
        {
        $MovePhoto = GCI $photoSourceLocation -File | Where-Object {$_.BaseName -contains $patient.Id}
        if($MovePhoto)
        {
        Move-Item $movePhoto.FullName -Destination $photoDropLocation 
        }
        #$MovePhoto.FullName
        Write-Progress -Activity "Processing photo matches." -Status "Progress:" -PercentComplete ($I/$patientRaw.count*100) #-End $Out
        $I++        
        }

$endDate = Get-Date     
$endDate

Ответы [ 2 ]

0 голосов
/ 24 января 2019

- это один из способов проверить соответствие между элементами в импорте CSV и элементами в коллекции имен файлов. Это зависит от того, как -match работает при использовании против коллекции вместо одного элемента.

# fake reading in a CSV file
#    in real life, use Import-CSV
$InStuff = @'
ID
Zero000
Alpha111
Bravo222
Charlie333
Santa666
'@ | ConvertFrom-Csv

# fake reading in a list of file names
#    in real life, use Get-ChildItem
$FileList = @(
    [System.IO.FileInfo]'Alpha111.jpg'
    [System.IO.FileInfo]'Charlie333.jpg'
    [System.IO.FileInfo]'Santa666.jpg'
    )

foreach ($IS_Item in $InStuff)
    {
    # this depends on there only being ONE matching file
    $FoundFile = $FileList -match $IS_Item.ID

    if ($FoundFile)
        {
        'Found a file for     = {0}' -f $IS_Item.ID
        '    The file name is = {0}' -f $FoundFile.Name
        }
        else
        {
        Write-Warning ('No matching file was found for {0}' -f $IS_Item.ID)
        }
    }

вывод ...

WARNING: No matching file was found for Zero000
Found a file for     = Alpha111
    The file name is = Alpha111.jpg
WARNING: No matching file was found for Bravo222
Found a file for     = Charlie333
    The file name is = Charlie333.jpg
Found a file for     = Santa666
    The file name is = Santa666.jpg
0 голосов
/ 24 января 2019

Поиск файла в каждой итерации, вероятно, делает его таким медленным.Вы должны получить файлы только один раз (посмотрите на комментарии):

НЕ ИСПЫТАНО

cls
($startDate = Get-Date)

$photoSourceLocation = "C:\Temp\Photos\Aggregate"
$photoDropLocation = "C:\Temp\Photos\Process"

$idQuery = "SELECT Id FROM SomeTable"
# select ids as plain string array (makes it easier for "contains")
$patientIds = @(Invoke-Sqlcmd -Query $idQuery -ServerInstance "SQLServer" -Database "DB" | foreach { $_.Id.ToString() })

# get all photos only once
# make it a list so we can remove items
$photos = [System.Collections.ArrayList]@(gci $photoSourceLocation -File)
$i = 0
foreach ($id in $patientIds) {
    # check the list of photos
    for ($p = 0; $p -lt $photos.Count; $p++) {
        $photos = $photos[$p]
        if ($photo.BaseName.Contains($id)) {
            # match found: move photo
            Move-Item $photo.FullName -Destination $photoDropLocation 
            # remove from list, so we have to search less next time
            $photos.RemoveAt($p)
            $p--
            # if there can only be one photo, we could stop looking here:
            # break
        }
    }
    $i++
    Write-Progress -Activity "Processing photo matches." -Status "Progress:" -PercentComplete ($i * 100 / $patientIds.Count)
}

($endDate = Get-Date)

Примечания:

  • Если вы должны зациклить идентификаторы вВнешний и фотографии во внутреннем цикле, или, скорее, наоборот, зависит от вашего варианта использования.
  • Снимите комментарий с «перерыва», если для идентификатора может быть только одна фотография
  • Удалениеэлементы из списка делают его короче, а проверяемых элементов меньше.Но это также требует изменения размера массива.Протестируйте его и сравните обе альтернативы, возможно , а не удаление элемента на самом деле быстрее.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...