Я пытаюсь скопировать атрибуты видеофайлов *.mkv *.mp4. Я нашел способ скопировать атрибуты файла, но он довольно медленный, так как вызывает Powershell для использования команд.
powershell ^(ls '!orig-file!'^).CreationTime = ^(ls '%%I'^).CreationTime
powershell ^(ls '!orig-file!'^).LastWriteTime = ^(ls '%%I'^).LastWriteTime
powershell ^(ls '!orig-file!'^).LastAccessTime = ^(ls '%%I'^).LastAccessTime
...................
%%I equals new-file for each FOR loop iteration
Есть ли способ сделать это быстрее без Powershell?
В противном случае я предполагаю, что можно было бы вызвать Powershell только один раз и скопировать все 3 или более атрибута в 1 строку? Я предполагаю, что чтение каждого атрибута файла по отдельности - единственный способ копирования, но я бы предпочел все атрибуты, если есть еще что копировать.
Обновлено: ПОЛНЫЙ КОД: (со всеми отмеченными/прокомментированными строками удалены) (Пакетное преобразование аудио видео из одного формата в другой)
@ECHO OFF
SETlocal
SET drive = "~dp0"
SET string=%CD%
SETlocal EnableExtensions EnableDelayedExpansion
SET "drive=G:"
SET ^"Exclude-AlltheseFolders=#snapshot,output^"
SET "Convert_Audio1=Y"
SET "Convert_TO=aac"
SET "Codec1=eac3"
SET "Codec2=flac"
SET "Codec3=dts" &SET "Codec4=pcm_s24le" &SET "Codec5=aac" &SET "Codec6=ac3"
SET "KeepExtraAudio_NoOrig=Y"
SET "KeepOrigAudio=N"
SET "OverWriteFiles=N"
SET "ExtractTime=Y"
SET "time_to_start_from=00:00:10" &SET "duration_to_capture=00:00:15"
SET "TempFilePath=C:\Windows\Temp\ffmpeg-CountingScript-AllFilesInCurrentDirlist%DT%--%HH%.%MM%.%SS%.txt"
IF !ExtractTime! == Y ( SET "FFmpgextractTime= -ss !time_to_start_from! -t !duration_to_capture!")
ECHO THIS IS JMK1
IF !OverWriteFiles! == Y (SET "OverWrite=-y ") ELSE (SET "OverWrite=-n ")
IF !Convert_Audio1! == Y (
IF !Convert_TO! == aac ( set "Convert_TO=libfdk_aac" )
SET "FFmpgConvertStream1=-c:a:0 !Convert_TO! -b:a:0 640k -disposition:a:0 default"
IF !KeepExtraAudio_NoOrig! == Y (
SET "FFmpgXtraStream=-c:a copy"
)
IF !KeepOrigAudio! == Y (
SET "KeepOrigAudio_ffMpg=-map 0:a:0? -c:a:0 copy"
SET "KeepExtraAudio_NoOrig=Y"
)
) ELSE (
SET "ConvertCodecs=1"
SET "KeepOrigAudio_ffMpg=-c:a:0 copy"
SET "KeepExtraAudio_NoOrig=Y"
)
SET "delm1=^\^>" /c:"^\^<"
SET ^"Exclude-Final=/c:"\^<!Exclude-AlltheseFolders!\^>"^"
SET ^"Exclude-Final=!Exclude-Final:,=%delm1%!^"
dir *.mkv *.mp4 /A-D-H /B /S |findstr /R %Exclude-Final% /v /i>%TempFilePath%
Echo: These are the folders being Excluded: "!Exclude-AlltheseFolders!"
SET "FINALCOMMAND = "
SETlocal EnableExtensions DisableDelayedExpansion
SET "ProgramFolder=C:\Program Files\FFmpeg-v2020\bin"
SET "ProbeOptions=-v quiet -select_streams a:0 -show_entries "stream^^=codec_name" -of json"
SET "FilesFound=0" & SET "FilesEncoded=0" & SET "output = "
for /F "delims = " %%I in (%TempFilePath%) do (
SET "output=%drive%%%~pI%%~nxI" & SET folder=%drive%%%~pI & SET "filename=%%~nxI" & SET /A FilesFound+=1
SETlocal EnableExtensions EnableDelayedExpansion
IF exist "%drive%%%~pIoutput\%%~nxI" (SET "Convert_Audio1=N") ELSE SET "Convert_Audio1=Y"
IF "!Convert_Audio1!" == "Y" (
SET "AudioCodec = " & SET "ConvertCodecs = "
for /F "eol = { tokens=1,2 delims=,:[ ]{} " %%B in ('""%ProgramFolder%\ffprobe.exe" %ProbeOptions% "%%I""') do (
IF "%%~B" == "codec_name" (
IF not defined AudioCodec (
SET "AudioCodec=%%~C"
)
IF "%%~C" == "%Codec1%" (SET "ConvertCodecs=1"
) else IF "%%~C" == "%Codec2%" (SET "ConvertCodecs=1" & ECHO Codec is: %%~C
) else IF "%%~C" == "%Codec3%" (SET "ConvertCodecs=1" & ECHO Codec is: %%~C
) else IF "%%~C" == "%Codec4%" (SET "ConvertCodecs=1" & ECHO Codec is: %%~C
) else IF "%%~C" == "%Codec5%" (SET "ConvertCodecs=1" & ECHO Codec is: %%~C
) else IF "%%~C" == "%Codec6%" (SET "ConvertCodecs=1" & ECHO Codec is: %%~C
)
)
)
)
IF !ConvertCodecs! == 1 (
ECHO [91m==!TIME!================[0m!Codec1! [94min[0m- %%I [91m=========[0m
)
IF !ConvertCodecs! == 1 (
IF /I "!output!" == "%%I" (
SET "output=%~dp0output\!filename!"
MKDIR "%~dp0output\"
) ELSE (
MKDIR "%drive%%%~pI"
)
SET "FINALCOMMAND=ffmpeg !OverWrite!-hide_banner%FFmpgextractTime% -loglevel quiet -hwaccel auto -stats -i "%%I" -map 0:v -map_metadata 0 -movflags use_metadata_tags -map 0:a? -map 0:s:0? -c:s:0 copy -c:v copy %FFmpgXtraStream% %FFmpgConvertStream1% %KeepOrigAudio_ffMpg% "!output!" "
ECHO this is the command1: !FINALCOMMAND!
!FINALCOMMAND!
ECHO [91m=====[0mCOMPLETE[91m===============[0m .
IF not %FilesEncoded% == 0 ECHO This one was a failure. Count Encoded so far: "%FilesEncoded%"
IF not errorlevel 1 SET /A FilesEncoded+=1
powershell ^(ls '!output!'^).CreationTime = ^(ls '%%I'^).CreationTime
powershell ^(ls '!output!'^).LastWriteTime = ^(ls '%%I'^).LastWriteTime
powershell ^(ls '!output!'^).LastAccessTime = ^(ls '%%I'^).LastAccessTime
for /F "delims = " %%p in ("!ConvertCodecs!") do (
ECHO THIS IS P: %%p
ENDLOCAL
SET /A FilesEncoded=%%p+FilesEncoded
)
) ELSE ( ECHO ##NOT PROCESSING##: !TIME! - %%I ## & ECHO [91m=====--[0mFILE ALREADY EXISTS! [91m======================[0m Next File [91m===========================[0m )
)
)
IF %FilesFound% == 1 ( SET "PluralS = " ) else SET "PluralS=s"
ECHO [91m***************************************************************************************[0m
ECHO Re-encoded %FilesEncoded% of %FilesFound% video file%PluralS%.
ECHO [91m***************************************************************************************[0m
endlocal
endlocal
endlocal
exit /b
Можете ли вы добавить часть цикла %%I
в свой пакетный скрипт? Вы могли бы по крайней мере объединить все 3 команды powershell в одну с точкой с запятой ;
Я знаком только с пакетом, и он кажется проще. "%%I" слишком длинный, чтобы включать его. Как будет выглядеть комбинированная команда powershell? Это: ` powershell ^(ls '!output!'^).CreationTime = ^(ls '%%I'^).CreationTime | ^(ls '!output!'^).LastWriteTime = ^(ls '%%I'^).LastWriteTime `
Не включайте его, и мы не сможем вам с этим помочь. Выбор ваш. Тем не менее, я вам скажу, что задача не может быть выполнена только с помощью встроенных утилит и команд пакетного файла, для этого потребуется вызвать другой язык сценариев и/или стороннюю утилиту.
Хорошо, добавлен полный код. Моя общая цель состояла в том, чтобы сделать пакет более эффективным и быстрым.
Я удалил кучу строк из вашего полного кода, т. е. тех, которые имеют неработающие метки и примечания. Это было необходимо, чтобы сделать ваш код более читабельным и с меньшей вероятностью отключить потенциальных помощников.
«Я знаком только с партиями, и это кажется проще». В конечном итоге время, потраченное на изучение PowerShell, определенно того стоит и окупится. Моя рекомендация - сделать прыжок.
Следующее копирует указанные атрибуты, используя один powershell.exe звонок:
Обратите внимание на использование gi
, встроенного псевдонима командлета Get-Item.
ls
- в Windows - это (к сожалению) встроенный псевдоним командлета Get-ChildItem (чье использование будет работать и здесь, и чей PowerShell-идиоматический псевдоним gci
); однако таких псевдонимов, названных в честь встроенных команд / утилит других оболочек / платформ, лучше избегать — см. Нижний раздел этого ответа для получения дополнительной информации.Включение всего (подразумеваемого) -Command
аргумента в "..."
устраняет необходимость ^
-экранирования отдельных символов.
powershell "$target = gi '!orig-file!'; $source = gi '%%i'; 'CreationTime', 'LastWriteTime', 'LastAccessTime' | foreach { $target.$_ = $source.$_ }"
Обратите внимание, что описанное выше может по-прежнему не работать в следующих случаях:
Если имя файла содержит само '
; если да, используйте \""...\""
(так в оригинале) вместо '...'
Если имя файла содержит [
и ]
; если это так, используйте gi -LiteralPath
вместо просто gi
, что подразумевает gi -Path
.
Люблю это, спасибо за обучение деталям!
Зачем вообще использовать cmd.exe? PowerShell намного лучше.