Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   удаление файлов по списку list.txt (http://forum.oszone.net/showthread.php?t=336076)

bidjo 07-08-2018 20:30 2825348

удаление файлов по списку list.txt
 
всем привет.
есть скрипт, в конце скрипта прописано удаление файлов которые указаны в списке list.txt
скрипт пашет, но выдает кучу ошибок в конце

в данный момент он выглядит так

Код:

@echo off
setlocal
1>nul chcp 1251
cd C:\vs
(for %%i in (*.jpg) do @echo file '%%i') > list.txt
ffmpeg -f concat -safe 0 -r 2 -i list.txt -threads 2 -vcodec libx264 -preset veryfast -qp 30 -tune grain -r 1 -framerate 1 30.avi
call
For /F "delims=" %%A In ('Dir "*.*" /A-D /B') Do (Echo %%~A)>>list.txt
For /f "tokens=*" %%i in (list.txt) do attrib -a %%i
attrib -a %0
del /aa /q /f *.*
del list.txt
pause

после отрабатывания скрипта, он все за собой чистит но в cmd ошибки
Код:

ошибка в формате параметра
и ошибок этих столько, сколько файлов я обрабатываю. а их несколько тысяч. в итоге скрипт отрабатывает за 1 минуту грубо говоря и 5 минут срет в лог ошибку формата параметра.
чоделатьпомогите

Iska 07-08-2018 21:54 2825355

Потому что у Вас какая-то сборная солянка в коде.

bidjo 08-08-2018 09:27 2825418

отсюда

Код:

@echo off
setlocal
1>nul chcp 1251
cd C:\vs
(for %%i in (*.jpg) do @echo file '%%i') > list.txt
ffmpeg -f concat -safe 0 -r 2 -i list.txt -threads 2 -vcodec libx264 -preset veryfast -qp 30 -tune grain -r 1 -framerate 1 30.avi

до сюда оно перемещается по cd , создает текстовый файл и по беря из него названия файлов, склеивает их в видео

Код:

call
следующая операция

отсюда
Код:

For /F "delims=" %%A In ('Dir "*.*" /A-D /B') Do (Echo %%~A)>>list.txt
For /f "tokens=*" %%i in (list.txt) do attrib -a %%i
attrib -a %0
del /aa /q /f *.*
del list.txt
pause

до сюда код спжен с просторов oszone написан для подчищения файлов после склеивания их в видосик.

alpap 08-08-2018 17:20 2825493

bidjo,
может так?
Код:

for %%a in (*.jpg) do ffmpeg -f concat -safe 0 -r 2 -i %%a -threads 2 -vcodec libx264 -preset veryfast -qp 30 -tune grain -r 1 -framerate 1 30.avi
del *.jpg
pause


bidjo 08-08-2018 21:35 2825517

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

Busla 08-08-2018 22:23 2825525

bidjo, я вас огорчу, но
Код:

For /F "delims=" %%A In ('Dir "*.*" /A-D /B') Do (Echo %%~A)>>list.txt
For /f "tokens=*" %%i in (list.txt) do attrib -a %%i
attrib -a %0
del /aa /q /f *.*
del list.txt

идентично не то что
Код:

del *.jpg
а даже
Код:

del *.*

Iska 09-08-2018 03:01 2825544

bidjo, так дело в том, что у Вас в файле list.txt не просто «файлы», а а) сначала идут записи вида:
Код:

file 'bla-bla-bla1.jpg'
file 'bla-bla-bla2.jpg'

file 'bla-bla-blaXXX.jpg'

и б) затем в нём же идут записи уже просто всех подряд файлов. Потому я и писал, что у Вас там сборная солянка в коде. Понятно, зачем собираются записи о *.jpg файлах в указанном выше виде — для последующей обработки их ffmpeg.exe. Но непонятно, зачем туда же потом дописываются записи обо всех подряд файлах. На кой шут для удаления задействуется архаичная и в целом порочная механика атрибуции (причём отдельной строкой — для самого пакетного файла :lol:). В предыдущем варианте (Любой язык - создание файла со списком файлов в папке) Вам требовалось собирать имена файлов пачками (дескать, ибо дюже много зараз), здесь же они собираются чохом — как понимать?

bidjo 09-08-2018 06:02 2825546

Цитата:

Цитата Busla
я вас огорчу, но »

и верно. не тестил на все файлы.
спасибо за подсказку.

Цитата:

Цитата Iska
так дело в том, что у Вас в файле list.txt не просто «файлы», а а) сначала идут записи вида:
и б) затем в нём же идут записи уже просто всех подряд файлов. Потому я и писал, что у Вас там сборная солянка в коде. Понятно, зачем собираются записи о *.jpg файлах в указанном выше виде — для последующей обработки их ffmpeg.exe. Но непонятно, зачем туда же потом дописываются записи обо всех подряд файлах. На кой шут для удаления задействуется архаичная и в целом порочная механика атрибуции (причём отдельной строкой — для самого пакетного файла ). В предыдущем варианте (Любой язык - создание файла со списком файлов в папке) Вам требовалось собирать имена файлов пачками (дескать, ибо дюже много зараз), здесь же они собираются чохом — как понимать? »

туда не записываются файлы все подряд, ток .jpg
в предыдущем варианте скрипт отрабатывает 960 файлов, в папке где их уже 50 и более тысяч. он для этого нужен. а скрипт concate нужен после, того как все устаканится и не будет такой чехарды.
Код:

For /F "delims=" %%A In ('Dir "*.*" /A-D /B') Do (Echo %%~A)>>list.txt
For /f "tokens=*" %%i in (list.txt) do attrib -a %%i
attrib -a %0
del /aa /q /f *.*

я честно спер с этого форума и он не работает как надо:) вот и прошу помощи

Цитата:

Цитата Iska
причём отдельной строкой — для самого пакетного файла [/post]

это сделано специально, что бы скрипт подчищал за собой.

Iska 09-08-2018 07:33 2825552

Цитата:

Цитата bidjo
туда не записываются файлы все подряд, »

А это:
Цитата:

Цитата bidjo
For /F "delims=" %%A In ('Dir "*.*" /A-D /B') Do (Echo %%~A)>>list.txt »

что тогда?


Цитата:

Цитата bidjo
в предыдущем варианте скрипт отрабатывает 960 файлов, в папке где их уже 50 и более тысяч. он для этого нужен. а скрипт concate нужен после, того как все устаканится и не будет такой чехарды. »

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

Вот Вам код на PowerShell:
Скрытый текст
Код:

Param (
    [System.String]$sSourceFolder = (Convert-Path -Path '.'),
    [System.Int32]$iLimit        = 100
)

if([System.IO.Directory]::Exists($sSourceFolder)) {
    do {
        $sFileList = [System.IO.Path]::Combine($sSourceFolder, [System.IO.Path]::GetRandomFileName())
    } until(-not [System.IO.File]::Exists($sFileList))

    $aFiles = Get-ChildItem -Path "$sSourceFolder\*.*" -File -Include '*.jpg', '*.jpeg', '*.jpe'

    if($aFiles.Count -gt 0) {
        $i = 0
        foreach($oFile in $aFiles) {
            Add-Member -InputObject $oFile -NotePropertyName Number -NotePropertyValue $i
            $i++
        }

        $aFiles | Group-Object -Property { [Math]::Floor([System.Int32]$_.Number / $iLimit) } | ForEach-Object -Process {
            $iListFileNumber = ([System.Int32]$_.Name) + 1
            $iFilesCount    = $_.Count

            $_.Group | ForEach-Object -Begin {
                $sContent = ''
            } -Process {
                $sContent += "file '$($_.Name)'`r`n"
            } -End {
                Out-File -InputObject $sContent -FilePath $sFileList -Encoding "Default" -NoNewline

                Start-Process `
                    -FilePath 'C:\Program Files\FFmpeg\bin\ffmpeg.exe' `
                    -ArgumentList "-y -f concat -safe 0 -r 2 -i $([System.IO.Path]::GetFileName($sFileList)) -threads 2 -vcodec libx264 -preset veryfast -qp 30 -tune grain -r 1 -framerate 1 Output$($iListFileNumber.ToString("0000")).avi" `
                    -WorkingDirectory $sSourceFolder `
                    -NoNewWindow -Wait

                Write-Host "$iFilesCount file(s) splitted into [Output$($iListFileNumber.ToString("0000")).avi]." -ForegroundColor Green
            }
        }

        [System.IO.File]::Delete($sFileList)

        switch($host.UI.PromptForChoice("Delete files?", "Delete all splitted jpeg files?", [System.Management.Automation.Host.ChoiceDescription[]] @("&Yes", "&No"), 1)) {
            0 {
                foreach($oFile in $aFiles) {
                    $oFile.Delete()
                    Write-Host "File [$($oFile.Name)] deleted."
                }
                Write-Host "Total $($aFiles.Count) file(s) deleted."
            }
            1 {
                # Nothing to do
            }
        }
    } else {
        Write-Host "Can't find any jpeg files in source folder [$sSourceFolder], nothing to do." -ForegroundColor Green
    }
} else {
    Write-Host "Can't find source folder [$sSourceFolder]." -ForegroundColor Red
}


который использует два параметра — путь к целевому каталогу (по умолчанию — текущий каталог) и число файлов в «пачке» (по умолчанию — 100). В указанном каталоге ищутся все jpeg-файлы, группируются по заданному числу файлов в «пачке», для каждой группы имён создаётся файл, который указывается аргументом при вызове ffmpeg.exe, после отработки которого обрабатывается следующая группа файлов до их исчерпания. В конце задаётся вопрос, следует ли удалять обработанные jpeg-файлы (чтобы у Вас была возможность перед их удалением предварительно посмотреть на получившиеся avi-файлы и оценить результат).

Пример процесса обработки двадцати шести jpeg-файлов в текущем каталоге, по 10 файлов в пачке:
Скрытый текст

Итог обработки:
Скрытый текст

Busla 09-08-2018 11:00 2825578

Цитата:

Цитата Iska
Вот Вам код на PowerShell »

зачем вы пишите такой лютый трэш и угар?

Iska 09-08-2018 11:29 2825585

Цитата:

Цитата Busla
зачем вы пишите такой лютый трэш и угар? »

Поясните, пожалуйста, подробнее.

Busla 09-08-2018 13:20 2825612

есть родные для PoSh типы данных string и int
проверку директории через [System.IO.Directory]::Exists допустим, понять можно - штатные способы "проглотят", например, путь к реестру
хотя в целом - это простой конвейер, если что-то не так с директорией, содержимым - сам командлет выдаст ошибку снабжённую всеми необходимыми атрибутами, на языке пользователя . "Плюнуть" на экран красный текст на иностранном языке - это для кого такое "удобство"? Оформляете в виде вызываемого скрипта, но он не формирует события ошибки.
Для создания временных файлов есть стандартные механизмы и места, для удаления файлов - тоже. Зачем вместо штатных команд использовать обращения к библиотекам .NET?
Синтетическое поле для каждого файла с номером - зачем?! - Они уже в пронумерованном массиве
Вместо округления результата деления и отдельный итератор для групп используют целочисленное деления и остаток от целочисленного деления.
Не надо явно указывать `r`n - это платформозависимое соглашение, а что PoSh, что ffmpeg работаею и на mac и на linux. Не надо в памяти формировать файлы - пишите сразу строки в файл
Пути к ffmpeg самое место в параметре по умолчанию, а не в середине скрипта
А вот результат работы ffmpeg как раз должен проверяться - сейчас если он не сможет создать видео (места на диске не хватило), скрипт всё равно бодро рапортует об успехе и удаляет исходные изображения. Наличие выходного файла тоже
Вместо велосипеда с PromptForChoice можно просто вызвать Remove-Item с параметром -Confirm. Вы так уверены, что выдавать на экран простыню из 960 имён удалённых файлов - хорошая идея? Если они важны - не лучше ли тогда использовать Write-Output - чтобы можно было их по необходимости передать по конвейеру и т.п.?
switch с единственным параметром тоже умиляет

Iska 09-08-2018 21:17 2825700

Busla, спасибо, ясно.

Цитата:

Цитата Busla
есть родные для PoSh типы данных string и int »

Поясните подробнее, пожалуйста. Если Вы про [string] и [int] — в чём их «родность» для PowerShell и в чём отличие от [System.String] и [System.Int32]?

Цитата:

Цитата Busla
проверку директории через [System.IO.Directory]::Exists допустим, понять можно - штатные способы "проглотят", например, путь к реестру »

Я полагаю сие более правильным подходом, нежели использование командлета Test-Path. Просто, надёжно и удобно.

Цитата:

Цитата Busla
хотя в целом - это простой конвейер, если что-то не так с директорией, содержимым - сам командлет выдаст ошибку снабжённую всеми необходимыми атрибутами, на языке пользователя . »

Не могу с Вами согласиться, коллега:
Скрытый текст

Красная портянка бывает и больше.

Цитата:

Цитата Busla
"Плюнуть" на экран красный текст на иностранном языке - это для кого такое "удобство"? »

Для себя. Это привычка.

Цитата:

Цитата Busla
Оформляете в виде вызываемого скрипта, но он не формирует события ошибки. »

Здесь Вы совершенно правы. Надо учиться, как это делать, и как это делать правильно.

Цитата:

Цитата Busla
Для создания временных файлов есть стандартные механизмы и места, »

Угу. Я использовал. Но у ffmpeg.exe есть свои принципы работы с путями, кодировками и конвеером :). Потому потребовалось выбирать — либо шашечки, либо ехать.

Цитата:

Цитата Busla
Зачем вместо штатных команд использовать обращения к библиотекам .NET? »

Как и в вышеупомянутом случае — потому что это проще, надёжнее и удобнее.

Цитата:

Цитата Busla
Синтетическое поле для каждого файла с номером - зачем?! - Они уже в пронумерованном массиве »

Потому что у меня возникла проблема — как вменяемо получить индекс элемента из массива объектов, полученного по Get-ChildItem. Можете показать, как сие сделать?

Цитата:

Цитата Busla
Вместо округления результата деления и отдельный итератор для групп используют целочисленное деления и остаток от целочисленного деления. »

Поясните, пожалуйста, подробнее.

Цитата:

Цитата Busla
Не надо явно указывать `r`n - это платформозависимое соглашение, а что PoSh, что ffmpeg работаею и на mac и на linux. »

Я не планирую работу скрипта под иные платформы.

Цитата:

Цитата Busla
Не надо в памяти формировать файлы - пишите сразу строки в файл »

Изначально я так и делал. Потом поменял логику работы. Что будет быстрее на большом количестве файлов — не проверял.

Цитата:

Цитата Busla
Пути к ffmpeg самое место в параметре по умолчанию, а не в середине скрипта »

Соглашусь полностью.

Цитата:

Цитата Busla
А вот результат работы ffmpeg как раз должен проверяться - сейчас если он не сможет создать видео (места на диске не хватило), скрипт всё равно бодро рапортует об успехе и удаляет исходные изображения. »

Соглашусь с оговоркой: всё равно надо смотреть полученный результат «глазками», и решение принимать по факту.

Цитата:

Цитата Busla
Наличие выходного файла тоже »

Видимо, мысль не закончена.

Цитата:

Цитата Busla
Вместо велосипеда с PromptForChoice можно просто вызвать Remove-Item с параметром -Confirm. »

Можно. Для отладки такие вещи:
Скрытый текст
годятся. Для работы — навряд ли: неподготовленного пользователя такие вопросы вводят в ступор.

Цитата:

Цитата Busla
Вы так уверены, что выдавать на экран простыню из 960 имён удалённых файлов - хорошая идея? »

Нет. Не уверен.

Цитата:

Цитата Busla
Если они важны - не лучше ли тогда использовать Write-Output - чтобы можно было их по необходимости передать по конвейеру и т.п.? »

Угу.

Цитата:

Цитата Busla
switch с единственным параметром тоже умиляет »

Привычка. Во-первых, понятно, что это выбор из вариантов. Во-вторых, сегодняшний switch с двумя ветвями завтра может потребовать трёх и более вариантов выбора, и проще добавить ветви в уже существующую структуру, нежели переписывать if на switch.

YuS_2 10-08-2018 13:42 2825803

Цитата:

Цитата Iska
как вменяемо получить индекс элемента из массива объектов, полученного по Get-ChildItem. »

Увы, вменяемо - вряд ли, нет встроенных инструментов. Но можно так:
Код:

function findex ($arr, $val) {
    for ($i=0;$i -lt $arr.count;$i++) {
        if($arr[$i] -eq $val){$i}
    }
}

но лучше ведь так, имхо:
Код:

[array]::indexof($arr.name,'name.ext')
хотя, сейчас дошли руки проверить и это:
Код:

$arr.name.indexof('name.ext')
работает...

Iska 10-08-2018 14:12 2825812

YuS_2, боюсь, с группировкой отобранных файлов мне это не особо поможет.

YuS_2 10-08-2018 14:54 2825826

Iska,
Да, в код не вчитывался, комментировал только то, что процитировано...
В общем, суть задачи пока не разбирал, ничего добавить не могу...
вечером, в спокойной обстановке гляну...

Busla 10-08-2018 17:02 2825837

Цитата:

Цитата Iska
как вменяемо получить индекс элемента из массива объектов, полученного по Get-ChildItem. Можете показать, как сие сделать? »

а зачем?! - индекс, чтобы по нему итерировать:
Код:

$aFiles = Get-ChildItem *.jpg -File

$iListFileNumber = 0
$iLimit = 8
$i = 0

while ($i -lt $aFiles.Length)
{
  $sListName = "$($iListFileNumber.ToString('000000')).lst"
  $iFileNumber = 0
  while ($iFileNumber -lt $iLimit -and $i -lt $aFiles.Length)
  {
   
    $i = $iListFileNumber * $iLimit + $iFileNumber
    Add-Content -Path $sListName -Value $aFiles[$i].Name
    $iFileNumber+=1

  }
  $iListFileNumber+=1
}

польская нотация придумана, для имитации пользовательских типов - чтобы килограммы с километрами не складывать, а не для дублирования системных

YuS_2 10-08-2018 18:24 2825847

Цитата:

Цитата Iska
боюсь, с группировкой отобранных файлов мне это не особо поможет. »

Не понял зачем там do ... until с рандомом, да и разбираться не стал...
Но, как минимум, тут:
Код:

    $aFiles = Get-ChildItem -Path "$sSourceFolder\*.*" -File -Include '*.jpg', '*.jpeg', '*.jpe'

    if($aFiles.Count -gt 0) {
        $i = 0
        foreach($oFile in $aFiles) {
            Add-Member -InputObject $oFile -NotePropertyName Number -NotePropertyValue $i
            $i++
        }

        $aFiles | Group-Object -Property { [Math]::Floor([System.Int32]$_.Number / $iLimit) }|...

действительно, есть лишнее действие (присвоение номеров элементам массива)...
Эквивалент:
Код:

    $aFiles = Get-ChildItem -Path "$sSourceFolder\*.*" -File -Include '*.jpg', '*.jpeg', '*.jpe'
    $aFiles | Group-Object -Property { [Math]::Floor($aFiles.name.indexof($_.name) / $iLimit) }


bidjo 10-08-2018 18:38 2825849

ух как тут жарко:)
спасибо большое за ответы. power shell конечно монструозный
что в .bat 10 строк, то в powershell целый том войны и мира

один вопрос
после формирования файла в list.txt есть куча строк с указанием файлов, из которых формируется видео.
выходное имя видео это то, что я задам, можно даже указать время сегодняшнее.
а нельзя ли, в качестве имени файла указать первую строчку и последнюю строчку list.txt?
допустим в папке лежат фото собачей будкии, а на выходе получилось не N.avi, а Будка злой собаки 01-01-2018_00h01m01s Будка злой собаки 01-01-2018_23h59m01s.avi

YuS_2 10-08-2018 19:15 2825853

Цитата:

Цитата bidjo
что в .bat 10 строк, то в powershell целый том войны и мира »

Это только так кажется... а на самом деле, powershell имеет значительно бОльшие возможности и инструменты, чем cmd, да и побыстрее работает, однако...
Например, прибавьте или отнимите, скажем, 7 дней к текущей дате в cmd, с учетом разного количества дней в месяцах, а также переход в новый/предыдущий месяц/год...
Вот, как это делается на powershell:
Код:

(get-date).adddays(7)
(get-date).adddays(-7)


Busla 11-08-2018 12:16 2825924

YuS_2, поиск индекса по значению в общем случае плохая затея: неэффективная и нужно быть уверенным в уникальности значений
да и вообще ненужная: кто сказал, что группировать можно только по свойствам объекта?

Код:

$oCount = @{ iValue = 0 }
$iLimit = 8

Get-ChildItem *.jpg | Group-Object { [Math]::DivRem($oCount.iValue++ , $iLimit, [ref]$null) }

единственное - потребовался небольшой хак, чтобы итератор стал ссылочным типом

Iska, Double - это двоичная дробь и двоичный сдвиг, поэтому отбрасывание дробной части может дать неожиданный результат.

Iska 11-08-2018 22:21 2825984

Цитата:

Цитата Busla
а зачем?! »

Мне — для группировки файлов «пачками».

По коду: с этим-то понятно. Минус такого подхода — в двойной проверке: общий цикл «для всего» и вложенная в него аналогичная проверка для того же условия, либо вложенным циклом, как у Вас (и так — да, красивее), либо простым условием с прерыванием цикла, как обычно делаю я. То бишь, делать — можно, но громоздко. Ладно, когда другого выхода нет (например, в том же WSH), а тут хотелось бы использовать конвеер и группировку.

Цитата:

Цитата Busla
польская нотация придумана, для имитации пользовательских типов - чтобы килограммы с километрами не складывать, а не для дублирования системных »

Не-не-не, это операция приведения типа, и я повторюсь, что не вижу принципиальной разницы что использовать — псевдоним или полное определение типа, [int] или [System.Int32], [string] или [System.String].

Цитата:

Цитата YuS_2
Не понял зачем там do ... until с рандомом, да и разбираться не стал...»

Дабы получить имя временного файла, которого гарантированно не существует в указанном каталоге. Чтобы быть абсолютно точно уверенным в данном факте.


Цитата:

Цитата YuS_2
Эквивалент: »

Спасибо, ясно. Будем знать.

Цитата:

Цитата Busla
YuS_2, поиск индекса по значению в общем случае плохая затея: неэффективная и нужно быть уверенным в уникальности значений »

Ну, значения-то у нас будут уникальные (в данном случае), а вот что поиск индекса по значению в массиве есть операция крайне медлительная — это факт.


Цитата:

Цитата Busla
да и вообще ненужная: кто сказал, что группировать можно только по свойствам объекта? »

Busla, браво! Мысленно снимаю шляпу. Казалось бы, элементарная вещь — но ведь до этого нужно ещё дойти, сообразить, что так — передавать по конвееру одно, а группировать по другой сущности, совсем не связанной с переданным по конвееру — тоже можно.

Цитата:

Цитата Busla
единственное - потребовался небольшой хак, чтобы итератор стал ссылочным типом »

Вот-вот. А я на этом упёрся и фсё, не сообразил, как сделать так, чтобы и овцы были целы, и волки сыты :(. Это вовсе не хак, это вполне нормальный способ обойти ограничения передачи аргумента по значению.

Цитата:

Цитата Busla
Iska, Double - это двоичная дробь и двоичный сдвиг, поэтому отбрасывание дробной части может дать неожиданный результат. »

Ну, тут по-хорошему надо смотреть, как хранятся числа в памяти — с фиксированной точкой или плавающей, как именно организовано вычисление операции деления. Совсем не копался на эту тему. Почему использовал Floor() — потому что не обнаружил в PowerShell оператора целочисленного деления, а DivRem() — тупо не нашёл :lol:.

bidjo 11-08-2018 23:38 2825995

эмм простите , а итоговый то скрипт какой?:)

Iska 11-08-2018 23:41 2825997

Цитата:

Цитата bidjo
а итоговый то скрипт какой? »

А итоговый — пишется по новым данным :lol:. Потом туда добавится и это:
Цитата:

Цитата bidjo
выходное имя видео это то, что я задам, можно даже указать время сегодняшнее.
а нельзя ли, в качестве имени файла указать первую строчку и последнюю строчку list.txt?
допустим в папке лежат фото собачей будкии, а на выходе получилось не N.avi, а Будка злой собаки 01-01-2018_00h01m01s Будка злой собаки 01-01-2018_23h59m01s.avi »


Iska 12-08-2018 02:35 2826014

Ну, вот, как-то так:
Скрытый текст
Код:

Param (
    [System.String]$Path2FFMpeg  = "$($ENV:ProgramFiles)\FFmpeg\bin\ffmpeg.exe",
    [System.String]$SourceFolder = '.',
    [System.Int32]$GroupBy      = 960
)

$SourceFolder = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($SourceFolder)

if([System.IO.Directory]::Exists($SourceFolder)) {
    if([System.IO.File]::Exists($Path2FFMpeg)) {
        do {
            $sFileList = [System.IO.Path]::Combine($SourceFolder, [System.IO.Path]::GetRandomFileName())
        } until(-not [System.IO.File]::Exists($sFileList))

        $hTable  = @{ iCount = 0 }
        $aFiles  = Get-ChildItem -Path "$SourceFolder\*.*" -File -Include '*.jpg', '*.jpeg', '*.jpe'

        if($aFiles.Count -gt 0) {
            $bSuccess = $true

            $aFiles | Group-Object { [Math]::DivRem($hTable.iValue++ , $GroupBy, [ref]$null) } | ForEach-Object -Process {
                $_.Group | ForEach-Object -Begin {
                    $sContent = ''
                } -Process {
                    $sContent += "file '$($_.Name)'`r`n"
                } -End {
                    $sOutputFileName = ($_.Group[0]).BaseName + ' - ' + ($_.Group[$_.Group.Count - 1]).BaseName + ".avi"

                    Out-File -InputObject $sContent -FilePath $sFileList -Encoding "Default" -NoNewline

                    $oCurrentCodePageEncoding = [Console]::OutputEncoding
                    [Console]::OutputEncoding = [System.Text.Encoding]::UTF8

                    $oProcess = Start-Process `
                        -FilePath $Path2FFMpeg `
                        -ArgumentList "-y -f concat -safe 0 -r 2 -i `"$([System.IO.Path]::GetFileName($sFileList))`" -threads 2 -vcodec libx264 -preset veryfast -qp 30 -tune grain -r 1 -framerate 1 `"$sOutputFileName`"" `
                        -WorkingDirectory $SourceFolder `
                        -NoNewWindow -Wait -PassThru
                   
                    [Console]::OutputEncoding = $oCurrentCodePageEncoding

                    if($oProcess.ExitCode -eq 0) {
                        Write-Host "`r`n$($_.Count) file(s) splitted into [$sOutputFileName].`r`n" -ForegroundColor Green
                    } else {
                        $bSuccess = $false
                        Write-Host "`r`nProbably an error [$($oProcess.ExitCode)] occured while try split files into [$sOutputFileName].`r`n" -ForegroundColor Red
                    }
                }
            }

            [System.IO.File]::Delete($sFileList)

            if($bSuccess) {
                switch($host.UI.PromptForChoice("Delete files?", "Delete all splitted jpeg files?", [System.Management.Automation.Host.ChoiceDescription[]] @("&Yes", "&No"), 1)) {
                    0 {
                        foreach($oFile in $aFiles) {
                            $oFile.Delete()
                            Write-Host "File [$($oFile.Name)] deleted." -ForegroundColor Green
                        }
                        Write-Host "`r`nTotal $($aFiles.Count) file(s) deleted." -ForegroundColor Green
                    }
                    1 {
                        # Nothing to do
                    }
                }
            }
        } else {
            Write-Host "Can't find any jpeg files in source folder [$SourceFolder], nothing to do." -ForegroundColor Green
        }
    } else {
        Write-Host "Can't find ffmpeg in [$Path2FFMpeg]." -ForegroundColor Red
    }
} else {
    Write-Host "Can't find source folder [$SourceFolder]." -ForegroundColor Red
}


Теперь первый параметр, Path2FFMpeg — путь к ffmpeg.exe (по умолчанию — C:\Program Files\FFmpeg\bin\ffmpeg.exe), второй параметр, SourceFolder — путь к целевому каталогу (по умолчанию — текущий каталог), третий параметр, GroupBy — число файлов в «пачке», из которой формируется видеофайл (по умолчанию — 960). Имена выходных видеофайлов формируются по указанному Вами принципу, нумерацию я оттуда вообще убрал.

Например, вызываем скрипт для обработки каталога 0008, находящегося в текущем каталоге, с группировкой файлов по двадцать штук:
Скрытый текст

Возможный результат

YuS_2 12-08-2018 09:22 2826029

Цитата:

Цитата Busla
неэффективная и нужно быть уверенным в уникальности значений»

это да... но если очень хочется, почему бы и нет? В смысле, что вариант использования, вполне присутствует. :)
А на счет уникальности - в данном, конкретном случае, всё на месте, в смысле уверенность в этом есть.

Цитата:

Цитата Busla
кто сказал, что группировать можно только по свойствам объекта? »

Вот! А это, как раз, пример творческого подхода. Вполне себе, ещё вариант и более быстродействующий...

Цитата:

Цитата Iska
Дабы получить имя временного файла, которого гарантированно не существует в указанном каталоге. Чтобы быть абсолютно точно уверенным в данном факте. »

Угу, сама идея-то понятна, непонятно с какой целью используется... ну, да это вообще не важно...

Цитата:

Цитата Iska
не вижу принципиальной разницы что использовать »

Это точно. Просто алиасы, как правило, короче в записи и поэтому удобнее использовать их, а разницы нет абсолютно.

Цитата:

Цитата Iska
потому что не обнаружил в PowerShell оператора целочисленного деления, а DivRem() — тупо не нашёл »

А мне вот powershell чем понравился... у него, всегда можно, не рыская по справочникам, дернуть встроенную справку...
Код:

man about_Arithmetic_Operators -full
- там, конечно, всего не найти, но очень многое, можно в памяти и не держать:
[int](5/2)

и так тоже можно:
Код:

[math]|gm -stat
имхо, это ведь очень удобно...

Iska 12-08-2018 12:12 2826048

Цитата:

Цитата YuS_2
Угу, сама идея-то понятна, непонятно с какой целью используется... ну, да это вообще не важно... »

Ну, как «зачем» — чтобы гарантировать, что данное полученное имя временного файла не совпадает с уже существующим. Да, вероятность совпадения имён теоретически околонулевая, но всё ж не нулевая.

Цитата:

Цитата YuS_2
А мне вот powershell чем понравился... у него, всегда можно, не рыская по справочникам, дернуть встроенную справку... »

А мне именно тем же — не понравился абсолютно: убого, неточно и недостаточно.

Busla 12-08-2018 14:25 2826066

Цитата:

Цитата YuS_2
там, конечно, всего не найти, но очень многое, можно в памяти и не держать:
[int](5/2) »

вот и попробуйте сделать:
Код:

[int](7/2)
к сожалению, совершенно неочевидна принадлежность к библиотеке Math
Цитата:

Цитата YuS_2
[math]|gm -stat »

Это чисто декоративная обёртка надо базовыми операциями

Цитата:

Цитата Iska
не вижу принципиальной разницы что использовать — псевдоним или полное определение типа, [int] или [System.Int32], [string] или [System.String] »

тот, кто понимает, пытается в каждом обращении к "низкоуровневым" библиотекам бэкэнда усмотреть подвох: почему именно Int32? - что завязано на конкретную разрядность? Или при вызове функций - что не так в реализации стандартного решения?
а тот, кто совсем не знаком с .NET не всегда поймёт что написано

Цитата:

Цитата Iska
хотелось бы использовать конвеер и группировку »

IMHO прелесть конвейера в потоковой схеме обработки данных: он начинает работать получив первую порцию данных и работает со скоростью самого медленного этапа обработки
он вообще может работать с данными, которых ещё нет в природе - подать на вход конвейера вывод датчика температуры и он потом годами будет переводить фаренгейты в градусы, сохранять в csv и слать алармы при критичных значениях

применительно к данному случаю - запустить скрипт, увидеть, что работает он уже третий день и досыпать туда ещё вчерашних фоток для склейки
(штатная) группировка ставит крест на этой светлой идее: она не знает, что группировка у нас по монотонному итератору, поэтому для анализа грузит в память весь список файлов

Iska, поделитесь, пожалуйста: как вы сделали длинный скриншот консоли?

YuS_2 12-08-2018 15:23 2826074

Цитата:

Цитата Busla
вот и попробуйте сделать »

а что не так? Нормальное округление :)
Причем, округление банкиров.
Так сказать:
[int]3.5 -eq [int]4.5

Цитата:

Цитата Busla
к сожалению, совершенно неочевидна принадлежность к библиотеке Math »

Отчего же? [int] - алиас [System.Int32]
Или Вы о чем?

Цитата:

Цитата Busla
Это чисто декоративная обёртка надо базовыми операциями »

Так ведь, что такое powershell, по сути? :)

Busla 12-08-2018 15:47 2826077

Цитата:

Цитата YuS_2
а что не так? Нормальное округление »

1) в других языках приведение float к int работает как floor
2) в данном контексте нарезка будет не на равные части, а ±1

Цитата:

Цитата YuS_2
Или Вы о чем? »

о том, что странно искать целочисленное деление в библиотеке Math

Iska 12-08-2018 16:48 2826080

Цитата:

Цитата Busla
вот и попробуйте сделать:
Код:

[int](7/2)
к сожалению, совершенно неочевидна принадлежность к библиотеке Math »

То бишь, получается, я был неправ, и на самом деле работает подобное:
Цитата:

value, rounded to the nearest 32-bit signed integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.


Сказка, просто сказка.

Цитата:

Цитата Busla
Или при вызове функций - что не так в реализации стандартного решения? »

Я лично охреневал от того, что в куче командлетов для вывода в файл тупо отсутствовала часть кодировок (потом, с течением времени, немного стали добавлять), реализация сего делалась разными параметрами. Ужас. Что мешало тупо использовать параметр типа [System.Text.Encoding] вместо набора строк?! И по сю пору (если в шестой версии не поменялось, не смотрел) — хочешь манипулировать наличием/отсутствием BOM и видом концов строк — забудь про командлеты, пользуй функции .Net.

Цитата:

Цитата Busla
а тот, кто совсем не знаком с .NET не всегда поймёт что написано »

«Нэ вэрю!» Без .Net на гольном PowerShell'е далеко не уедешь, шаг влево, шаг вправо — и приехали. Да и просто даже для того, чтобы мало-мальски представлять, как это вообще работает, нужен .Net.

Цитата:

Цитата Busla
Iska, как вы сделали длинный скриншот консоли? »

ShareX (ShareX - Screen capture, file sharing and productivity tool), из меню в трее — \Захват\Захват с прокруткой…, выбрать внутреннюю часть окна консоли PowerShell (так, чтобы ползунок прокрутки буфера экрана консоли оставался за пределами выбранного), «Начать захват», дождаться конца прокрутки и захвата, «Загрузить/сохранить в соответствии с настройками задач после захвата, скадрировать (обрезать) изображение, появившееся в редакторе. Если предварительно уменьшить для текущего окна консоли размер буфера экрана так, чтобы всё вмещалось и не было ничего лишнего — можно обойтись и без обрезания.

Удобная штука. Я перешёл на ShareX с PicPick.


Цитата:

Цитата Busla
о том, что странно искать целочисленное деление в библиотеке Math »

А если не в Math — то где :unsure:?!

YuS_2 12-08-2018 18:04 2826092

Цитата:

Цитата Busla
1) в других языках приведение float к int работает как floor
2) в данном контексте нарезка будет не на равные части, а ±1 »

1. Дык, а зачем на них ориентироваться? да и при чем тут powershell, если это дотнет...
"Windows PowerShell автоматически выбирает числовой тип платформы .NET"
2. Это да и именно поэтому Ваш вариант [math]::divrem, наиболее красивый... имхо

Цитата:

Цитата Busla
о том, что странно искать целочисленное деление в библиотеке Math »

Всё равно не понял. Искать можно где угодно, если оно есть и его можно использовать...
В powershell, например, оно есть, а вот использовать возвращаемый остаток, в данном случае неприемлемо... т.е. поискать его надо в более других доступных местах, да хоть в [math]::truncate - почему нет?

YuS_2 12-08-2018 18:24 2826095

Цитата:

Цитата Iska
Без .Net на гольном PowerShell'е далеко не уедешь, шаг влево, шаг вправо — и приехали. Да и просто даже для того, чтобы мало-мальски представлять, как это вообще работает, нужен .Net. »

Конечно, нужен, а без .net powershell будет калекой... да и многие командлеты построены на нем.


Время: 22:20.

Время: 22:20.
© OSzone.net 2001-