Файл foreach PowerShell в папке, использующий много памяти - PullRequest
4 голосов
/ 11 мая 2011

Я довольно плохо знаком с PowerShell и программированием, поэтому уверен, что этот код можно оптимизировать еще больше.

Тем не менее, моя самая большая проблема с этим кодом заключается в том, что он помещает данные из цикла foreach в память. Каков наилучший способ предотвратить это?

Я начал переписывать этот скрипт из скрипта, который нашел здесь: PowerShell: удаление файлов старше x дней

Редактировать: Кстати, в каждом TargetFolder около 60 000 ~ файлов.

## Set Window Title
$title = $Host.UI.RawUI.WindowTitle
$titdef = $title
$Host.UI.RawUI.WindowTitle = "Checking files. Do NOT close " + "($title)"

## Debug (0=Nothing, 1=Extended log, 2=Extended log+Screen)
$Debug = "2"

## Log file
$log = "C:\status\status.txt"
Add-Content $log "nul"

## Clear log before adding new data 
Remove-Item $log

## Folders to check
$TargetFolder1 = “\\server\c$\BiztalkProjects\UDC\output\ume”
$TargetFolder2 = “\\server\c$\BiztalkProjects\UDC\output\upp”

## Required stuff
$Now = Get-Date
$Days = “2”
$TwoDays = $Now.AddDays(-$Days)
$Folder1 = get-childitem $TargetFolder1 -include *
$Folder2 = get-childitem $TargetFolder2 -include *

## Window Message
"Checking for files newer than $Days days in:"
"$TargetFolder1"
"$TargetFolder2"
""
"This may take 5-15 minutes . . . (Will commit about 250MB~ RAM during the period)"

## Reset variable $OK to "0"
$OK = 0

if ($Debug -eq "2") {"Check1"}
foreach ($File in $Folder1) {
    $FileLastWrite = $File.LastWriteTime
    if ($File.LastWriteTime -le $TwoDays) {
        $OK = $OK + "0"
        if ($Debug -eq "2") {
            "OK + 0 (=$OK) $File ($FileLastWrite)"
            }
    } else {
        $OK = $OK + "1"
        if ($Debug -eq "2") {
            "OK + 1 (=$OK) $File ($FileLastWrite)" 
            }
    }
}
if ($Debug -eq "2") {"Check2"}
foreach ($File in $Folder2) {
    $FileLastWrite = $File.LastWriteTime
    if ($File.LastWriteTime -le $TwoDays) {
        $OK = $OK + "0"
        if ($Debug -eq "2") {
            "OK + 0 (=$OK) $File ($FileLastWrite)"
            }
    } else {
        $OK = $OK + "1"
        if ($Debug -eq "2") {
            "OK + 1 (=$OK) $File ($FileLastWrite)" 
            }
    }
}
if ($OK -gt "0") {
    if ($Debug -eq "2") {
        ""
        "Found $OK file(s) newer than $Days days"
        }
    Add-Content $log "OK"
    if ($Debug -ge "1") {
        Add-Content $log "Found $OK file(s) newer than $Days days"
        }
    }
    else {
        if ($Debug -eq "2") {
        ""
        "Found $OK file(s) newer than $Days days"
        }
    Add-Content $log "Error"
    if ($Debug -ge "1") {
        Add-Content $log "Found $OK file(s) newer than $Days days"
        }
    }
$Host.UI.RawUI.WindowTitle = $titdef

Эта версия работает. Спасибо всем, кто помог!

## Set Window Title
$title = $Host.UI.RawUI.WindowTitle
$titdef = $title
$Host.UI.RawUI.WindowTitle = "Checking files. Do NOT close " + "($title)"

## Debug (0=Nothing, 1=Extended log, 2=Extended log+Screen)
$Debug = "2"

## Log file
$log = "C:\status\status.txt"
Add-Content $log "nul"

## Clear log before adding new data 
Remove-Item $log

## Folders to check
$TargetFolder1 = “\\server\c$\BiztalkProjects\UDC\output\ume”
$TargetFolder2 = “\\server\c$\BiztalkProjects\UDC\output\upp”

## Required stuff
$Now = Get-Date
$Days = “2”
$TwoDays = $Now.AddDays(-$Days)

## Window Message
"Checking for files newer than $Days days in:"
"$TargetFolder1"
"$TargetFolder2"
""
"This may take 5-15 minutes . . ."

## Reset variable $OK to "0"
$OK = 0

get-childitem $TargetFolder1,$TargetFolder2 -filter *.xml |where-object {
    $FileLastWrite = $_.LastWriteTime
    if ($FileLastWrite -le $TwoDays) {
        $OK = $OK + "0"
    } else {
        $OK = $OK + "1"
    }
}
if ($OK -gt "0") {
    if ($Debug -eq "2") {
        ""
        "Found $OK file(s) newer than $Days days"
        }
    Add-Content $log "OK"
    if ($Debug -ge "1") {
        Add-Content $log "Found $OK file(s) newer than $Days days"
        }
    }
    else {
        if ($Debug -eq "2") {
        ""
        "Found $OK file(s) newer than $Days days"
        }
    Add-Content $log "Error"
    if ($Debug -ge "1") {
        Add-Content $log "Found $OK file(s) newer than $Days days"
        }
    }
$Host.UI.RawUI.WindowTitle = $titdef

Ответы [ 2 ]

4 голосов
/ 11 мая 2011

Что-то вроде

 $TS=(Get-Date).AddDays(-2)
 $COUNT = (get-childitem -recurse path1,path2 |where-object {$_.LastWriteTime -gt $TS}|measure-object).Count
 if ($COUNT > 0) { Echo "There are $COUNT files" }

может быть лучше (я не проверял его на производительность)

4 голосов
/ 11 мая 2011

Попробуйте:

$Folder1 = get-childitem $TargetFolder1 -filter *.xml

Гораздо быстрее, чем при использовании include (для большого набора файлов).Или даже лучше:

get-childitem $TargetFolder1 -filter *.xml | % {}

РЕДАКТИРОВАТЬ

Теперь я вижу, ваши проблемы связаны с include!Если вам нужно использовать подстановочные знаки и ни регулярные выражения для получения дочернего элемента, используйте вместо этого filter.Гораздо эффективнее, потому что не использует сопоставление регулярных выражений.

Попробуйте:

$Folder1 = get-childitem $TargetFolder1 -filter *

, даже если не очень понятно, что вы там фильтруете (или хотите включить) ... все?Может быть, вам вообще не нужен подстановочный знак.


По моему скромному мнению, лучший способ предотвратить цикл foreach в памяти - это трубопровод .Однако из-за характера вашего сценария (многие вложенные элементы управления внутри цикла) это не так просто.

Попробуйте с:

$Folder1 | % {
  # ...
}

, даже если я сомневаюсь, что это улучшит производительность.


или:

get-childitem $TargetFolder1 -include * | % {
  # ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...