将视频文件从图片目录移动到视频目录

Move video files from Pictures directory to Video directory

我的照片导入工具 (Picasa) 在从我的 phone 和相机中导入照片和视频方面表现出色。我喜欢的是它根据每个 photo/video 的照片拍摄日期在 Pictures 目录下创建一个子文件夹。所以你最终得到了这个结构:

C:\Pictures17-02-01\DSC_0001.jpg
C:\Pictures17-02-01\DSC_0002.jpg
C:\Pictures17-02-01\DSC_0003.mp4 <--- problem

唯一的问题是它将视频放在图片下的相同结构中。

因此,我想使用一个批处理脚本来查找所有视频文件(.mp4、.avi、.mov)并将其从 C:\Pictures 目录移动到 C:\Videos 目录,但是还有日期子文件夹.... 即

Move C:\Pictures17-02-01\DSC_0003.mp4 to C:\Videos17-02-01\DSC_0003.mp4

请注意,C:\Videos 下可能存在也可能不存在日期子文件夹。

此外,由于这些是大型视频文件,而且数量很多,为了速度和磁盘,我更喜欢实际执行移动而不是复制然后删除的进程 space 利用率,因为我几乎 space(重新组织这些文件后,我将归档到 NAS)。

我也更喜欢使用 RoboCopy、xcopy 或 xxcopy,因为我现在已经在我的机器上使用它们了。如果使用 PowerShell 脚本更容易,我可以学习它是否容易做到。

最终解决方案 我使用了 Mofi 的答案,但对其进行了一些增强以添加一个函数来计算目录字符串长度

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Define folder with the pictures which is never deleted.
set "PicturesFolder=D:\Users\Chad\PicturesTest"

rem get string length of source directory to later use in a substring type function
call :strlen PicturesFolderDirectoryLength PicturesFolder
echo PicturesFolderDirectoryLength = %PicturesFolderDirectoryLength%

rem Change the current directory to directory with the pictures.
cd /D "%PicturesFolder%"

rem Search recursive in this directory for video files with
rem file extension AVI, MOV, MP4 or MPG and move those files.
for /F "delims=" %%I in ('dir /A-D /B /S *.avi *.mov *.mp4 *.mpg 2^>nul') do call :MoveVideo "%%I"

rem Discard all environment variables defined in this batch code
rem and restore initial current directory before exiting batch file.
endlocal
goto :EOF

rem MoveVideo is a subroutine called with name of current
rem video file name with full path by the FOR loop above.

rem It first defines target path for video file depending on source path
rem by removing the backslash at end and concatenating C:\Videos with the
rem source path omitting the first 11 characters which is C:\Pictures.

rem Then the target directory structure is created with redirecting the
rem error message output by command MD to handle STDERR in case of the
rem target directory already exists to device NUL to suppress it.

rem Next the video file is moved from source to target folder with silently
rem overwriting an already existing file with same name in target folder
rem because of using option /Y. Remove this option if a video file should
rem be kept in pictures folder and an error message should be displayed in
rem case of a video file with same name already existing in target folder.

rem Last the source folder is removed if it is completely empty which means
rem it does not contain any file or subfolder. All parent folders up to the
rem pictures folder are also removed if each parent folder is also empty
rem after deletion of an empty folder.

rem The subroutine is exited with goto :EOF and execution of batch file
rem continues in main FOR loop above with next found video file.

:MoveVideo
set "SourcePath=%~dp1"
set "SourcePath=%SourcePath:~0,-1%"
ECHO SourcePath=%SourcePath%

CALL SET "SourceSubFolder=%%SourcePath:~%PicturesFolderDirectoryLength%%%"
ECHO SourceSubFolder=%SourceSubFolder%

set "TargetPath=D:\Users\Chad\VideosTest%SourceSubFolder%"
echo TargetPath=%TargetPath%

md "%TargetPath%" 2>nul
move /Y "%~1" "%TargetPath%\%~nx1" >nul

:DeleteSourceFolder
rd "%SourcePath%" 2>nul
if errorlevel 1 goto :EOF
for /F "delims=" %%D in ("%SourcePath%") do set "SourcePath=%%~dpD"
set "SourcePath=%SourcePath:~0,-1%"
if /I not "%SourcePath%" == "%PicturesFolder%" goto DeleteSourceFolder
goto :EOF

:strlen <resultVar> <stringVar>
(   
    setlocal EnableDelayedExpansion
    set "s=!%~2!#"
    set "len=0"
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
        if "!s:~%%P,1!" NEQ "" ( 
            set /a "len+=%%P"
            set "s=!s:~%%P!"
        )
    )
)
( 
    endlocal
    set "%~1=%len%"
    exit /b
)
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
XCOPY /T "%sourcedir%" "%destdir%"
FOR %%x IN (mp4 mov) DO (
 FOR /f "tokens=1*delims=>" %%a IN (
  'XCOPY /Y /s /d /F /L "%sourcedir%\*.%%x" "%destdir%"'
 ) DO IF "%%b" neq "" (
  SET "topart=%%b"
  SET "frompart=%%a"
  ECHO(MOVE /y "!frompart:~0,-2!" "!topart:~1!"
 )
)    


GOTO :EOF

您需要更改 sourcedirdestdir 的设置以适合您的情况。

所需的 MOVE 命令仅 ECHOed 用于测试目的。 确认命令正确后,将ECHO(MOVE 更改为MOVE 以实际移动文件。附加 >nul 以禁止报告消息(例如 1 file moved

第一个 xcopy 创建所需的子树,第二个使用 /L 选项列出而不是复制文件

%%x 上的循环将 %%x 分配给所需的扩展名。内部 xcopy 的输出将是 fullsourcefilename -> fulldestinationfilename 形式,因此需要使用 > 作为分隔符对其进行解析,from-filename 到 %%a,to-filename 到 %%b。如果未设置 %%b,则这是需要忽略的 xcopy 报告的最后一行(已复制 n 个文件)。 tofrom 文件名需要删除不需要的但幸运的是常量字符串。

有趣的是,在目标文件名已经存在的情况下,似乎无法使用 xcopy 来抑制提示。

这里是保留目录结构的文件移动任务的注释批处理代码。

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Define folder with the pictures which is never deleted.
rem Note: ~11 in third line of subroutine MoveVideo must be
rem       replaced by ~length of the folder path defined here.
set "PicturesFolder=C:\Pictures"

rem Change the current directory to directory with the pictures.
cd /D "%PicturesFolder%"

rem Search recursive in this directory for video files with
rem file extension AVI, MOV, MP4 or MPG and move those files.
for /F "delims=" %%I in ('dir /A-D /B /S *.avi *.mov *.mp4 *.mpg 2^>nul') do call :MoveVideo "%%I"

rem Discard all environment variables defined in this batch code
rem and restore initial current directory before exiting batch file.
endlocal
goto :EOF

rem MoveVideo is a subroutine called with name of current
rem video file name with full path by the FOR loop above.

rem It first defines target path for video file depending on source path
rem by removing the backslash at end and concatenating C:\Videos with the
rem source path omitting the first 11 characters which is C:\Pictures.

rem Then the target directory structure is created with redirecting the
rem error message output by command MD to handle STDERR in case of the
rem target directory already exists to device NUL to suppress it.

rem Next the video file is moved from source to target folder with silently
rem overwriting an already existing file with same name in target folder
rem because of using option /Y. Remove this option if a video file should
rem be kept in pictures folder and an error message should be displayed in
rem case of a video file with same name already existing in target folder.

rem Last the source folder is removed if it is completely empty which means
rem it does not contain any file or subfolder. All parent folders up to the
rem pictures folder are also removed if each parent folder is also empty
rem after deletion of an empty folder.

rem The subroutine is exited with goto :EOF and execution of batch file
rem continues in main FOR loop above with next found video file.

:MoveVideo
set "SourcePath=%~dp1"
set "SourcePath=%SourcePath:~0,-1%"
set "TargetPath=C:\Videos%SourcePath:~11%"
md "%TargetPath%" 2>nul
move /Y "%~1" "%TargetPath%\%~nx1" >nul

:DeleteSourceFolder
rd "%SourcePath%" 2>nul
if errorlevel 1 goto :EOF
for /F "delims=" %%D in ("%SourcePath%") do set "SourcePath=%%~dpD"
set "SourcePath=%SourcePath:~0,-1%"
if /I not "%SourcePath%" == "%PicturesFolder%" goto DeleteSourceFolder
goto :EOF

此批处理文件还会删除 C:\Pictures 中的所有文件夹,这些文件夹在移动视频文件后变为空文件夹。但它不会删除启动批处理文件时已经为空的文件夹。

要了解使用的命令及其工作原理,请打开命令提示符 window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

  • cd /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • md /?
  • move /?
  • rd /?
  • rem /?
  • set /?
  • setlocal /?

另请阅读有关 Using Command Redirection Operators 的 Microsoft 文章,了解 >nul2>nul 的解释。在主 FOR 循环中,重定向运算符 > 使用脱字符 ^ 转义,在解析 FOR[=67 时被解释为文字字符=] 命令行,后来在 FOR.

执行 DIR 命令行时作为重定向运算符