一、总体概述
这两个文件是一对配套使用的 Windows 批处理(.bat)脚本 (以 .txt 形式保存),共同实现"从 3 台 FTP 服务器并行批量下载指定目录下所有文件"的功能:
| 文件 | 角色 | 核心职责 |
|---|---|---|
ftp_download_.bat |
主脚本 | 配置参数、为每台服务器建目录、并行启动下载任务、等待并汇总结果 |
ftp_download_task.bat |
辅助脚本 | 被主脚本按服务器逐台调用,负责"登录验证→列目录→逐个文件下载" |
两者必须放在同一目录下运行,主脚本依赖辅助脚本,缺一不可。
bash
@echo off
chcp 936 >nul
REM ============================================================
REM FTP 单服务器下载辅助脚本(由主脚本并行调用)
REM 参数: %1=IP %2=用户名 %3=密码 %4=远程目录 %5=保存根目录
REM 方式: 列目录(含登录验证) -> 逐个下载
REM 保存: 根目录\IP\远程目录层级(如 10.0.2.51\AAAA\BBBB\)
REM ============================================================
setlocal enabledelayedexpansion
set "IP=%~1"
set "FTP_USER=%~2"
set "FTP_PASS=%~3"
set "REMOTE_BASE=%~4"
set "SCRIPT_DIR=%~5"
REM 保存目录 = 根目录\IP + 远程路径层级(/ 转为 \)
set "DL_DIR=%SCRIPT_DIR%%IP%%REMOTE_BASE:/=\%"
if not exist "%DL_DIR%" mkdir "%DL_DIR%"
echo [%IP%] 开始连接 %REMOTE_BASE% ...
set "LIST_FILE=%DL_DIR%\_listing.tmp"
set "ERR_FILE=%DL_DIR%\_curl_err.tmp"
REM 1. 列目录(同时验证用户名密码)
curl.exe -sS --connect-timeout 15 --max-time 120 --ftp-pasv --user "%FTP_USER%:%FTP_PASS%" "ftp://%IP%%REMOTE_BASE%/" -o "%LIST_FILE%" 2>"%ERR_FILE%"
set "RC=%errorlevel%"
if not "%RC%"=="0" (
set "ERRTXT="
for /f "usebackq delims=" %%E in ("%ERR_FILE%") do set "ERRTXT=%%E"
echo [%IP%] 连接失败,curl 错误码: %RC%
if "%RC%"=="67" (
echo [%IP%] 提示: 用户名或密码错误,请检查 FTP_USER / FTP_PASS 配置。
) else if "%RC%"=="7" (
echo [%IP%] 提示: 无法连接服务器,请检查网络或 IP 地址是否可达。
) else if "%RC%"=="28" (
echo [%IP%] 提示: 连接超时,请检查服务器状态。
) else (
echo [%IP%] 提示: !ERRTXT!
)
del "%ERR_FILE%" >nul 2>nul
exit /b %RC%
)
del "%ERR_FILE%" >nul 2>nul
if not exist "%LIST_FILE%" (
echo [%IP%] 列目录失败
exit /b 1
)
REM 统计文件数
set "COUNT=0"
for /f "usebackq tokens=* delims=" %%L in ("%LIST_FILE%") do (
set "LINE=%%L"
if not "!LINE:~0,1!"=="d" (
set "FNAME="
for %%F in (%%L) do set "FNAME=%%F"
if defined FNAME set /a COUNT+=1
)
)
if "%COUNT%"=="0" (
echo [%IP%] 登录成功,但目录为空或无可下载文件。
del "%LIST_FILE%" >nul 2>nul
exit /b 0
)
echo [%IP%] 登录成功,共 %COUNT% 个文件,开始下载...
set "N=0"
set "FAIL=0"
REM 2. 逐行解析并下载(跳过目录行、跳过空行)
for /f "usebackq tokens=* delims=" %%L in ("%LIST_FILE%") do (
set "LINE=%%L"
if not "!LINE:~0,1!"=="d" (
set "FNAME="
for %%F in (%%L) do set "FNAME=%%F"
if defined FNAME (
set /a N+=1
echo [%IP%] [!N!/%COUNT%] 下载中: !FNAME!
curl.exe -sS --connect-timeout 15 --max-time 3600 --ftp-pasv --user "%FTP_USER%:%FTP_PASS%" "ftp://%IP%%REMOTE_BASE%/!FNAME!" -o "%DL_DIR%\!FNAME!" 2>"%ERR_FILE%"
if !errorlevel! neq 0 (
set /a FAIL+=1
set "ERRTXT2="
for /f "usebackq delims=" %%E in ("%ERR_FILE%") do set "ERRTXT2=%%E"
echo [%IP%] 文件下载失败: !FNAME! 原因: !ERRTXT2!
)
)
)
)
del "%LIST_FILE%" >nul 2>nul
del "%ERR_FILE%" >nul 2>nul
if "%FAIL%"=="0" (
echo [%IP%] 全部下载完成: 共 %COUNT% 个文件, 失败 0 个。
) else (
echo [%IP%] 下载完成: 共 %COUNT% 个文件, 失败 %FAIL% 个。
)
exit /b %FAIL%
bash
@echo off
chcp 936 >nul
setlocal enabledelayedexpansion
title FTP batch download BBBB
REM ============================================================
REM FTP 批量下载脚本(主脚本)
REM 功能:同时下载 3 台服务器 /AAAA/BBBB/ 下所有数据
REM 保存:分别存入本脚本同目录下
REM 10.0.2.51\AAAA\BBBB\
REM 10.0.3.51\AAAA\BBBB\
REM 10.0.5.51\AAAA\BBBB\
REM 用法:直接双击运行;如需改密码或日期,修改下方变量
REM 依赖:同目录需存在 ftp_download_task.bat 辅助脚本
REM ============================================================
set "FTP_USER=xxxx"
set "FTP_PASS=yyyy"
set "REMOTE_BASE=/AAAA/BBBB"
set "IP_LIST=10.0.2.51 10.0.3.51 10.0.5.51"
set "SCRIPT_DIR=%~dp0"
if not exist "%SCRIPT_DIR%ftp_download_task.bat" (
echo [ERROR] 缺少辅助脚本 ftp_download_task.bat,请将其与本脚本放在同一目录。
pause
exit /b 1
)
echo 脚本目录: %SCRIPT_DIR%
echo 远程目录: %REMOTE_BASE%
echo 目标主机: %IP_LIST%
echo.
REM ---- 为每台服务器创建带远程路径层级的文件夹,并后台并行启动下载 ----
for %%I in (%IP_LIST%) do (
if not exist "%SCRIPT_DIR%%%I%REMOTE_BASE%" mkdir "%SCRIPT_DIR%%%I%REMOTE_BASE%"
start "FTP_DL_%%I" /min cmd /c ""%SCRIPT_DIR%ftp_download_task.bat" %%I "%FTP_USER%" "%FTP_PASS%" "%REMOTE_BASE%" "%SCRIPT_DIR%""
)
REM ---- 等待所有 curl 下载进程结束 ----
:waitloop
tasklist /fi "imagename eq curl.exe" 2>nul | find /i "curl.exe" >nul
if not errorlevel 1 (
timeout /t 2 /nobreak >nul
goto waitloop
)
echo.
echo ============ 全部下载任务结束 ============
for %%I in (%IP_LIST%) do (
if exist "%SCRIPT_DIR%%%I%REMOTE_BASE%" (
for /f %%C in ('dir /b "%SCRIPT_DIR%%%I%REMOTE_BASE%" 2^>nul ^| find /c /v ""') do echo [%%I] 已下载文件数: %%C
)
)
pause
endlocal
二、文件 1:主脚本 ftp_download_.bat
1. 用途
同时从 3 台服务器(10.0.2.51、10.0.3.51、10.0.5.51)的远程目录 /AAAA/BBBB/ 下载所有数据,并按"IP\远程路径层级"分别保存到脚本所在目录下的子文件夹中(如 10.0.2.51\AAAA\BBBB\)。
2. 关键配置变量
FTP_USER=xxxx、FTP_PASS=yyyy:FTP 账号密码(当前为占位符,使用前需替换为真实凭据)REMOTE_BASE=/AAAA/BBBB:远程下载源目录IP_LIST=10.0.2.51 10.0.3.51 10.0.5.51:3 台目标服务器 IPSCRIPT_DIR=%~dp0:脚本自身所在目录(作为下载保存根目录)
3. 执行流程
- 初始化 :
@echo off关闭命令回显,chcp 936切换 GBK 中文代码页,setlocal enabledelayedexpansion开启延迟变量扩展,窗口标题设为 "FTP batch download BBBB"。 - 依赖检查 :检测同目录是否存在
ftp_download_task.bat,缺失则报错并退出(exit /b 1)。 - 建目录 + 并行启动 :
for循环遍历 3 个 IP,为每台创建本地保存目录(如10.0.2.51\AAAA\BBBB),再用start /min cmd /c以最小化新窗口后台并行方式调用辅助脚本,传入 IP、用户名、密码、远程目录、保存根目录 5 个参数。 - 等待结束 :
:waitloop标签轮询tasklist检测curl.exe进程是否还在运行,每 2 秒检查一次,直到所有下载进程退出。 - 结果汇总 :用
dir /b | find /c /v统计每个服务器目录下的已下载文件数并打印,最后pause暂停等待用户查看。
三、文件 2:辅助脚本 ftp_download_task.bat
1. 用途
单台服务器的下载执行单元,由主脚本并行调起 3 个实例。接收 5 个参数:%1=IP、%2=用户名、%3=密码、%4=远程目录、%5=保存根目录。
2. 执行流程
- 准备保存目录 :将远程路径中的
/转换为\,拼出本地目录根目录\IP\AAAA\BBBB,不存在则创建。 - 列目录(兼作登录验证) :用
curl.exe以被动模式(--ftp-pasv)访问ftp://IP/AAAA/BBBB/,连接超时 15 秒、总超时 120 秒,目录清单输出到临时文件_listing.tmp,错误写入_curl_err.tmp。 - 错误处理 :若 curl 返回非 0,针对不同错误码给出中文诊断提示:
- 67 → 用户名或密码错误
- 7 → 无法连接服务器(网络/IP 不可达)
- 28 → 连接超时
- 其他 → 原样输出 curl 错误文本
- 统计文件数 :解析目录清单,跳过以
d开头的目录行和空行,统计可下载文件个数;若为 0 则提示"目录为空"并正常退出。 - 逐个下载 :对每个文件再次调用
curl.exe下载(单文件总超时放宽到 3600 秒),实时打印进度[序号/总数] 下载中: 文件名;失败时累计失败数并打印原因。 - 收尾 :删除两个临时文件,汇总"共 N 个文件,失败 M 个",以失败数作为退出码(
exit /b %FAIL%)。
四、两文件的关系与协作方式
主脚本(配置+调度)
│ for 每台服务器: start /min 后台窗口
├──> 辅助脚本实例1 (10.0.2.51) ── curl 列目录→逐文件下载
├──> 辅助脚本实例2 (10.0.3.51) ── 并行执行
└──> 辅助脚本实例3 (10.0.5.51) ── 并行执行
│ 轮询 curl.exe 进程直到全部结束
└──> 汇总各目录文件数 → pause
- 主脚本只管调度与汇总,不直接做 FTP 操作;真正的连接、验证、下载全部由辅助脚本完成。
- 并行策略:3 台服务器同时下载,互不阻塞;主脚本通过监测
curl.exe进程判断整体完成。
五、技术要点与注意事项
- 编码 :两脚本均执行
chcp 936,脚本文件需保存为 GBK/ANSI 编码,中文提示才能正常显示。 - 延迟扩展 :均使用
setlocal enabledelayedexpansion,循环内用!变量!取值,这是批处理循环中正确处理动态变量的关键。 - 依赖 curl :下载核心是
curl.exe(Win10 1803+ 自带),脚本本身不含 FTP 客户端程序。 - 只下载文件、不递归子目录 :辅助脚本会跳过目录行(以
d开头),仅下载/AAAA/BBBB/一级目录下的文件。 - 凭据为占位符 :当前
FTP_USER=xxxx、FTP_PASS=yyyy需在使用前修改为主脚本头部的真实账号密码;另建议注意脚本明文存密码的安全风险,避免随意外传。 - 健壮性设计:含依赖检查、登录失败诊断(区分密码错/网络不通/超时)、空目录提示、单文件失败不中断整体、最终成功/失败计数,容错较完善。