Использование пакетного копирования для копирования атрибутов файла (по крайней мере, Created, LastWrite, LastAccess) из 1 файла во 2-й

Я пытаюсь скопировать атрибуты видеофайлов *.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

Зачем вообще использовать cmd.exe? PowerShell намного лучше.

Bill_Stewart 19.01.2023 21:30

Можете ли вы добавить часть цикла %%I в свой пакетный скрипт? Вы могли бы по крайней мере объединить все 3 команды powershell в одну с точкой с запятой ;

Cpt.Whale 19.01.2023 23:04

Я знаком только с пакетом, и он кажется проще. "%%I" слишком длинный, чтобы включать его. Как будет выглядеть комбинированная команда powershell? Это: ` powershell ^(ls '!output!'^).CreationTime = ^(ls '%%I'^).CreationTime | ^(ls '!output!'^).LastWriteTime = ^(ls '%%I'^).LastWriteTime `

hsgg4 19.01.2023 23:25

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

Compo 19.01.2023 23:32

Хорошо, добавлен полный код. Моя общая цель состояла в том, чтобы сделать пакет более эффективным и быстрым.

hsgg4 19.01.2023 23:39

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

Compo 20.01.2023 11:32

«Я знаком только с партиями, и это кажется проще». В конечном итоге время, потраченное на изучение PowerShell, определенно того стоит и окупится. Моя рекомендация - сделать прыжок.

Bill_Stewart 20.01.2023 17:51
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Следующее копирует указанные атрибуты, используя один powershell.exe звонок:

  • Обратите внимание на использование gi, встроенного псевдонима командлета Get-Item.

  • Включение всего (подразумеваемого) -Command аргумента в "..." устраняет необходимость ^-экранирования отдельных символов.

powershell "$target = gi '!orig-file!'; $source = gi '%%i'; 'CreationTime', 'LastWriteTime', 'LastAccessTime' | foreach { $target.$_ = $source.$_ }"

Обратите внимание, что описанное выше может по-прежнему не работать в следующих случаях:

  • Если имя файла содержит само '; если да, используйте \""...\"" (так в оригинале) вместо '...'

    • См. этот ответ для получения дополнительной информации.
  • Если имя файла содержит [ и ]; если это так, используйте gi -LiteralPath вместо просто gi, что подразумевает gi -Path.

Люблю это, спасибо за обучение деталям!

hsgg4 20.01.2023 16:21

Другие вопросы по теме