Доброго времени суток, читатель!
Недавно мне подкинули довольно простенькую на первый взгляд задачку: Надо перемешать около 1000 фотографий для системы голосований.
Вручную заниматься этим — дело неблагодарное. Нужен какой-нибудь миленький скрипт.
PowerShell оказался идеальным вариантом: ставить что-то стороннее вроде python не хотелось, а с .bat файлами я за свою жизнь так и не подружился.
Пожалуй начнем.
Названия фотографий были важны и их хотелось сохранить. Я решил убрать их в свойства файла («Сводка» для WinXp, «Подробно» для Win7). Тем более голосовалка написана на sharepoint, а он умеет подхватывать «Название» из свойств файла. Оказалось очень удобно.
Для редактирования свойств файла был использован компонент OLE File Property Reader 2.1 (В папке с примерами vb7 есть обертка библиотеки для .net), благо уже был установлен на машине. Компонент предназначен для офисных документов, но и для картинок подошел.
Собственно скрипт:
[System.Reflection.Assembly]::LoadFrom('c:DsoFileSourceVb7DemobinInterop.DSOFile.dll')
function SetSummary-Name([string] $folder, [string]$pattern = '*.*')
{
$files = [System.IO.Directory]::GetFiles($folder, $pattern)
foreach ($f in $files)
{
$oled = New-Object -TypeName DSOFile.OleDocumentPropertiesClass
$oled.Open($f, $false, [DSOFile.dsoFileOpenOptions]::dsoOptionDefault)
$sp = $oled.SummaryProperties
$sp.Title = $f.Substring($f.lastindexof('') + 1, $f.lastindexof('.') - $f.lastindexof('') - 1)
$oled.close($true)
}
}
SetSummary-Name -folder 'c:photo'
Далее перейдем к перемешиванию:
Можно было генерировать числовые имена, но вдруг очень сильно захотелось изобрести велосипед сложной конструкции.
# Заменяет имя файла на произвольный набор букв
function RandomName([string]$path)
{
$length = 20 # длинна нового имени
$sb = New-Object -TypeName System.Text.StringBuilder
for($i=0; $i -lt $length; $i++)
{
# Тут меня отпустило, велосипед удался...
[char]$ch = [Convert]::ToChar([Convert]::ToInt32([Math]::Floor(26 * $rand.NextDouble() + 65)))
$tmp = $sb.Append($ch) # Append возвращает ненужную нам информацию, выкидываем ее в $tmp
}
$name = $path.Substring($path.lastindexof('') + 1, $path.lastindexof('.') - $path.lastindexof('') - 1)
$sb = $sb.ToString().ToLower()
return $path.Replace($name, $sb)
}
function MixFiles([string]$From, [string]$pattern = '*.*')
{
$files = [System.IO.Directory]::GetFiles($from, $pattern)
foreach($f in $files)
{
$path = RandomName -path $f
# На всякий случай проверим,
while([System.IO.File]::Exists($path))
{
# Чтобы знать, если такое случится
$path
$path = RandomName -path $f
}
# Для красоты покажем старые и новые имена
Write-Host ($f + ' -> ' + $path)
[System.IO.File]::Move($f, $path)
}
}
$rand = New-Object -TypeName Random
MixFiles -from 'c:test' -pattern '*.jpg'
Спасибо за внимание, надеюсь буду кому-нибудь полезен.
Автор: Halflling