返回列表 发帖

[FTP] 普遍适用的FTP文件夹上传下载批处理函数

之前有说FTP的mput和mget命令能上传下载文件夹,但是不能对子文件夹进行操作,这里给出的两个函数 FTPXPut 和 FTPXGet 可以递归操作子文件夹里面的文件。
过程从会在临时文件夹生成一些文件,之后会自动删除。
注意:你可以修改指定部位的代码,达到更个性化的目的,因为他们已经精确到了对每个文件夹和文件的操作,具体位置详见注释。

下面是一个在批处理文件中调用它们的实例,两个下载的例子可以直接运行,因为是访问公共资源;上传的例子需要自己修改,如果你有某个FTP服务器的帐号。
ftpXgetXput_sample.bat 链接: https://pan.baidu.com/s/1iQ1AlKS1xsOiVhlqLnZVGA?pwd=qqdt
@echo off
REM 上传下载测试(匿名用户 anonymous 密码任意)
REM 下载一个 UNIX 目录列表类型服务器上的文件夹
echo ***************** 开始从 UNIX 服务器下载文件夹 **************************
set rp=/pub/mirrors/ubuntu/pool/main/l/language-pack-zh/
call :FTPXGet ftp.cs.stanford.edu anonymous Spring  %rp% .\zh
pause
REM 下载一个 MS-DOS 目录列表类型服务器上的文件夹
echo ***************** 开始从 WINDOWS 服务器下载文件夹 ***********************
set rp=/Products/Windows/Windows95/CDRomExtras/AdministrationTools/
call :FTPXGet ftp.microsoft.com   anonymous Brother %rp% D:\ms
pause
echo ***************** 开始上传文件夹到远程 FTP 服务器 ***********************
call :FTPXPut 10.120.6.43 was1 admin "%userprofile%\Favorites" /MyFavoriteSites
pause
goto :EOF
REM 上传一个本地文件夹到 FTP 服务器
REM ============================================================================
REM [FTPXPut]   (C)2011  Spring
REM 将一个本地文件夹 %4 上传为 FTP 服务器 %1 的 %5 文件夹,用户名 %2,密码 %3。
REM 你可以修改 Folder Operation 和 File Operation 的内容达到个性化的目的。
REM ============================================================================
:FTPXPut
if [%5]==[] (
    echo ERROR : 参数不足,已退出。
    goto :EOF
)
setlocal enabledelayedexpansion
REM 存放 FTP 命令行的临时文件
set $__ftpq="%temp%\CommandQueue%random%.txt"
REM 本地文件夹绝对路径,以 "\" 结尾
set $__ldir=%~f4\
set $__ldir=!$__ldir:\\=\!
REM 远程文件夹绝对路径,以 "/" 结尾
set $__rdir=/%5/
set $__rdir=!$__rdir:\=/!
set $__rdir=!$__rdir:"=!
set $__rdir=!$__rdir://=/!
REM 检测基本条件
echo 本地目录:!$__ldir!
echo 远程目录:!$__rdir!
echo 初始化...
if not exist "!$__ldir!" (
    echo ERROR : 找不到文件夹 "!$__ldir!",已退出。
    goto :EOF
)
REM 本地文件夹顶层目录的长度,在获取相对路径时会用到
set /a LEN_SKIP=0
for /l %%i in (0,1,1000) do (
    if not "!$__ldir:~%%i,1!"=="" (
        set /a LEN_SKIP+=1
    )
)
REM 创建 FTP 命令行文件并写入登录命令和建立目标顶层文件夹的命令
(echo open %1
echo %2
echo %3
echo binary)>!$__ftpq!
echo 正在映射文件夹并添加FTP传输队列...
REM 先进行文件夹及子文件夹查询
for /f "delims=" %%a in ('echo !$__ldir!^&dir /s /b /ad "!$__ldir!"') do (
    REM 当前本地路径
    set "$__lcp=%%a\"
    set "$__lcp=!$__lcp:\\=\!"
    REM 相对路径   
    set "$__lcrp=!$__lcp:~%LEN_SKIP%!"
    REM 最顶层的文件夹路径全被截掉了,因此加个判断避免出错
    if not "!$__lcrp!"=="" set "$__lcrp=!$__lcrp:\=/!"
    echo !$__lcp!  --^>  !$__rdir!!$__lcrp!
    REM 添加建立远程文件夹并将远程目录切换至此文件夹的命令
    REM ==================== Folder Operation ====== Start =====================
    echo mkdir "!$__rdir!!$__lcrp!">>!$__ftpq!
    echo cd "!$__rdir!!$__lcrp!">>!$__ftpq!
    REM ==================== Folder Operation ======  End  =====================
    REM 对每个子文件夹进行文件查询并生成操作命令
    for /f "delims=" %%z in ('dir /b /a-d "!$__lcp!" 2^>nul') do (
        REM ================= File Operation ====== Start ======================
        echo put "!$__lcp!%%z">>!$__ftpq!
        REM ================= File Operation ======  End  ======================
    )
)
REM 写入退出 FTP 的命令
echo bye>>!$__ftpq!
REM 启动传输过程
echo 启动FTP文件传输队列...
ftp -v -s:!$__ftpq!
echo 文件传输完成。
REM 清除过程中产生的临时文件
echo 正在清除临时文件...
del !$__ftpq!
echo 操作完成。
endlocal
goto :EOF
REM 下载一个 FTP 文件夹到本地
REM ============================================================================
REM  [FTPXGet]   (C)2011  Spring
REM  建议使用封装好的过程 :FTPXGet ,它会帮你调用 :GenerateFTPGetCommand 去启
REM  动 :GenerateUnixFTPGetCommandCore ,确保其正确运行并且清理产生的临时文件,
REM  但是你可以修改 Folder Operation 和 File Operation 的内容达到个性化的目的。
REM ============================================================================
:FTPXGet
set $ftpp="%temp%\FTP_Paths.txt"
set $ftpq="%temp%\CommandQueue.txt"
if [%1]==[] (set /p  $srv=FTP站点: ) else (set  $srv=%1)
if [%2]==[] (set /p $user=用户名:  ) else (set $user=%2)
if [%3]==[] (set /p  $pwd=密码:    ) else (set  $pwd=%3)
if [%4]==[] (set /p $rdir=远程目录:) else (set $rdir=%4)
if [%5]==[] (set /p $ldir=本地目录:) else (set $ldir="%~f5")
echo 远程路径:%$rdir%
echo 本地路径:%$ldir:"=%
call :GenerateFTPGetCommand %$srv% %$user% %$pwd% %$rdir% %$ldir% %$ftpp% %$ftpq%
echo 启动FTP文件传输队列...
ftp -v -s:%$ftpq%
echo 文件传输完成。
del %$ftpp%,%$ftpq%
goto :EOF
REM 启动 :GenerateUnixFTPGetCommandCore 递归过程并且负责清理其产生的临时文件,
REM FTP服务器=%1,用户名=%2,密码=%3,远程目录=%4,本地目录=%5
REM 远程子目录列表=%6,保存FTP命令传输队列的文件=%7
:GenerateFTPGetCommand
if [%7]==[] (
    echo ERROR : 参数不足,已退出。
    goto :EOF
)
echo 初始化...
set $_srv=%1
set $_user=%2
set $_pwd=%3
REM 清除特定类型的缓存文件
if exist "%temp%\*.$ftp_cmd" del /q "%temp%\*.$ftp_cmd"
if exist "%temp%\*.$dir_rst" del /q "%temp%\*.$dir_rst"
if exist "%temp%\*.$dir_gen" del /q "%temp%\*.$dir_gen"
if exist %6 del /f /q %6
REM 登录到服务器执行一次 dir 命令,根据输出文本判断目录列表类型.
REM 注意:通过 PASV 命令只能识别服务器类型,而目录列表类型是可以人为更改的。
echo 正在分析服务器类型...
(echo open %$_srv%
echo %$_user%
echo %$_pwd%
echo prompt
echo verbose
echo binary
echo dir / "%temp%\$roo$.$dir_rst"
echo bye)>"%temp%\ftpcmd.$ftp_cmd"
ftp -s:"%temp%\ftpcmd.$ftp_cmd">nul
REM MS-DOS格式列表以日期开头,第一个字符为数字,UNIX格式以属性开头,不含数字。
REM 根据此特征可以查看第一个字符进行判断服务器采取的是哪一种列表格式。
findstr "^[0-9]" "%temp%\$roo$.$dir_rst" 1>nul 2>&1
set $_typeUnixOrMSDOS=%errorlevel%
set /p $=目录列表样式:<nul
if %$_typeUnixOrMSDOS% equ 0 (echo MS-DOS) else (echo Unix)
REM 创建文件传输队列的FTP命令行文件并写入开头
echo 正在映射文件夹并添加FTP传输队列...
(echo open %$_srv%
echo %$_user%
echo %$_pwd%
echo binary)>%7
REM 清空两个影响判断的关键变量
set "BASE_FOLDER="
set "LEN_SKIP="
REM 已经做好了准备工作,启动过程
call :GenerateUnixFTPGetCommandCore %$_typeUnixOrMSDOS% %$_srv% %$_user% %$_pwd% %4 %5 %6 %7
REM 写入结束命令
echo bye>>%7
REM 清除临时文件
echo 正在清除临时文件...
del /q %temp%\*.$ftp_cmd,%temp%\*.$dir_rst,%temp%\*.$dir_gen
goto :EOF
REM 以用户名 %3 密码 %4 登录目录列表类型为 %1 的 FTP 服务器 %2 ,
REM 获取其目录 %5 下的子文件夹路径以及文件路径,准备下载为本地目录 %6 ,
REM 文件夹列表追加到文件 %7 中,FTP命令序列追加到 %8 中。
REM 执行过程中在 %temp% 中产生后缀为 .$ftp_cmd .$dir_rst .$dir_gen 的临时文件。
REM     注意:远程 FTP 服务器目录列表输出样式必须为 UNIX 样式。
:GenerateUnixFTPGetCommandCore
setlocal enabledelayedexpansion
if [%8]==[] (
    echo ERROR : 参数不足,已退出。
    goto :EOF
)
set $__srv=%2
set $__user=%3
set $__pwd=%4
REM 去掉远程路径中的双引号以及重复的斜杠
set $__rcp=%5/
set $__rcp=!$__rcp:\=/!
set $__rcp=!$__rcp:"=!
set $__rcp=!$__rcp://=/!
REM 此路径下执行 FTP 命令 dir 的结果保存到的临时文件
set $__cl=!$__rcp:/=$!
REM 远程目录文件夹列表
set $__rst=%7
REM 保存最终要生成的 FTP 命令队列的文件
set $__cq=%8
REM 因为可能是重复使用,故不采取 defined 来判断 BASE_FOLDER 和 LEN_SKIP
if "!BASE_FOLDER!"=="" set BASE_FOLDER=!$__rcp!
REM 得到基础路径的长度,以便之后只截取相对路径
if "!LEN_SKIP!"=="" (
    set /a LEN_SKIP=0
    for /l %%i in (0,1,1000) do (
        if not "!BASE_FOLDER:~%%i,1!"=="" (
            set /a LEN_SKIP+=1
        )
    )
)
REM 去掉本地路径中的双引号以及重复的斜杠
set $__lcp=%6\!$__rcp:~%LEN_SKIP%!
set $__lcp=!$__lcp:/=\!
set $__lcp=!$__lcp:"=!
set $__lcp=!$__lcp:\\=\!
REM 追加一条路径信息到结果
echo !$__rcp!  --^>  !$__lcp!
echo !$__rcp!>>!$__rst!
REM ============= Folder Operation ====== Start =================
if not exist "!$__lcp!" md "!$__lcp!">>!$__cq!
echo lcd "!$__lcp:~0,-1!">>!$__cq!
REM ============= Folder Operation ======  End  =================
REM 生成获取当前远程目录下文件列表的 FTP 命令行并执行
(echo open !$__srv!
echo !$__user!
echo !$__pwd!
echo prompt
echo verbose
echo binary
REM 如果目录列表格式是 MS-DOS 格式,则切换为 UNIX 以便统一处理
if %1 equ 0 echo quote site dirstyle
echo dir "!$__rcp!" "%temp%\!$__cl!.$dir_rst"
echo bye)>"%temp%\ftpcmd.$ftp_cmd"
ftp -s:"%temp%\ftpcmd.$ftp_cmd" 1>nul
REM 属性第一位是字符 d 的是文件夹,查找不是 d 开头的行,得到所有文件名,生成命令
for /f "tokens=1,2,3,4,5,6,7,8,* delims= " %%a in ('type "%temp%\!$__cl!.$dir_rst"^|findstr "^^[^^d]"') do (
    REM ============= File Operation ====== Start =================
    if not "%%i"=="" echo get "!$__rcp!%%i">>!$__cq!
    REM ============= File Operation ======  End  =================
)
REM 如果找到 d 开头的行,说明此目录还有子目录
type "%temp%\!$__cl!.$dir_rst"|findstr "^d" 1>nul
if !errorlevel!==0 (
    REM 将子目录路径存放到临时文件
    for /f "tokens=1,2,3,4,5,6,7,8,* delims= " %%a in ('type "%temp%\!$__cl!.$dir_rst"^|findstr "^^d"') do (
        REM 去掉父目录(..),当前目录(.),否则会死循环
        if not "%%i"=="" if not "%%i"=="." if not "%%i"==".." echo !$__rcp!/%%i>>"%temp%\!$__cl!.$dir_gen"
    )
    REM 对所有子目录调用自身,遍历所有文件夹
    if exist "%temp%\!$__cl!.$dir_gen" for /f "usebackq delims=" %%a in ("%temp%\!$__cl!.$dir_gen") do (
        call :GenerateUnixFTPGetCommandCore %1 !$__srv! !$__user! !$__pwd! "%%a" %6 !$__rst! !$__cq!
    )
)
endlocal
goto :EOFCOPY

回复 2# HMB0002


可以参考一下这个思路:批处理实现FTP整站上传
http://bbs.bathome.net/thread-12525-1-1.html
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

返回列表