【问题标题】:Move video files from Pictures directory to Video directory将视频文件从图片目录移动到视频目录
【发布时间】:2017-07-10 13:51:26
【问题描述】:

我的照片导入工具 (Picasa) 在从我的手机和相机导入照片和视频方面做得很好。我喜欢的是它根据每张照片/视频的拍照日期在图片目录下创建一个子文件夹。所以你最终得到了这个结构:

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

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

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

Move C:\Pictures\2017-02-01\DSC_0003.mp4 to C:\Videos\2017-02-01\DSC_0003.mp4

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

此外,由于这些是大型视频文件,而且数量很多,为了速度和磁盘空间利用率,我更喜欢实际执行移动而不是复制然后删除的进程空间不足(重新组织这些文件后,我将归档到 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
)

【问题讨论】:

  • 我很尴尬地向一个拥有近 2,000 名代表的用户提出这个问题,但是......你能告诉我们你到目前为止所做的尝试吗?

标签: batch-file xcopy robocopy batch-rename


【解决方案1】:

这是此文件移动任务的注释批处理代码,并保持目录结构。

@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 中的所有文件夹,这些文件夹在移动视频文件后变为空。但它不会删除在启动批处理文件时已经为空的文件夹。

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

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

另请阅读有关Using Command Redirection Operators 的Microsoft 文章,了解&gt;nul2&gt;nul。在主 FOR 循环中,重定向运算符 &gt; 使用插入符号 ^ 进行转义,以便在解析 FOR 命令行时解释为文字字符,然后在解析时作为重定向运算符FOR 执行DIR 命令行。

【讨论】:

  • 删除空的源目录就像一个魅力和不错的功能!!!加上优秀的代码文档!我稍微增强了您的解决方案,使其具有计算源文件夹目录长度的功能,以免对其进行硬编码,以防我以后想将其用作其他任务的基线。请参阅我在原始问题中更新的最终答案。
【解决方案2】:
@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 以实际移动文件。附加&gt;nul 以禁止报告消息(例如1 file moved

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

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

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

【讨论】:

  • 在带有 XCOPY 命令的两行中,目标路径应为 "%destdir%\",末尾带有反斜杠,以使 XCOPY 清楚地表明目标是一个目录而不是一个文件,以避免被问到目标是一个文件还是一个目录。在这种情况下,也使用 XCOPY 选项 /I 将避免被询问目标是文件还是目录。但是/I 仅适用于复制多个文件,而目标末尾的反斜杠也适用于复制单个文件。
  • 使用 XCOPY 将单个(隐藏)文件复制到目标文件夹(尚不存在)的目标文件夹中以不同的名称出现提示。我在BATCH file asks for file or folder 发布了针对此特殊问题的解决方案,因为提示取决于语言,并且如果批处理文件应该独立于语言自动回答提示,则需要额外的代码。
  • @mofi :第一个 xcopy,已授予。第二个 - 不,因为它已经作为目录存在。自从第一个 xcopy 创建目标目录后,目标目录就会存在。似乎(我的解释)xcopyy 开关不起作用。我想我应该向 M$ 提及,但修复它的机会 - 好吧,如果我先玩彩票,我会成为亿万富翁......
  • 第一个 XCOPY 命令行只是在目标目录中创建目录树也需要/Y 以避免提示覆盖已经存在的 *.mp4 文件,尽管 *.mp4文件根本没有被复制。确实很有趣,虽然使用了/T,所以没有文件被复制,XCOPY 要求覆盖目标目录中的现有文件。
猜你喜欢
  • 1970-01-01
  • 2015-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
相关资源
最近更新 更多