不使用商业第三方FTP组件,VBScript上传文件至FTP服务器的问题
解决VBScript Shell.Application FTP上传的CopyHere问题
我来帮你排查这个FTP上传的问题——用Shell.Application的CopyHere方法做FTP传输确实容易踩一些隐性的坑,尤其是参数配置和连接逻辑上的问题。你怀疑objFTP.CopyHere objItem, copyType有问题是对的,咱们一步步拆解:
1. 先修正CopyHere的参数组合
你用的copyType = 16只设置了FOF_NOCONFIRMATION(不显示确认对话框),但脚本运行时通常需要更“安静”的模式,避免弹窗或错误提示中断流程。建议换成更合适的参数组合:
Const FOF_SILENT = 4 ' 不显示进度对话框 Const FOF_NOCONFIRMATION = 16 ' 不显示确认对话框 Const FOF_NOERRORUI = 1024 ' 不显示错误提示 Const copyType = FOF_SILENT + FOF_NOCONFIRMATION + FOF_NOERRORUI
这些参数组合能让上传过程在后台静默执行,避免因为交互弹窗导致脚本卡住。
2. 修复FTP连接的逻辑问题
直接在URL里拼接用户名密码的方式,部分FTP服务器可能不支持(比如包含特殊字符的密码),而且如果连接失败,objFTP会变成Nothing,后续调用CopyHere直接报错。建议改成先连接FTP服务器,再登录并切换目录:
' 先连接FTP服务器根目录 strFTP = "ftp://" & FTPHost Set objFTP = oShell.NameSpace(strFTP) If objFTP Is Nothing Then Wscript.Echo "无法连接到FTP服务器: " & FTPHost Exit Sub End If ' 执行登录 objFTP.Items().Parent.Logon FTPUser, FTPPass ' 切换到目标目录 Set objFTP = objFTP.Folders.Item(FTPDir) If objFTP Is Nothing Then Wscript.Echo "FTP目标目录不存在: " & FTPDir Exit Sub End If
这种方式比直接拼接URL更可靠,还能提前排查连接和目录存在的问题。
3. 优化错误处理和等待逻辑
你注释掉了On Error Resume Next,但脚本运行时需要捕获错误;另外固定80秒等待太死板,建议改成循环检查上传状态(比如对比本地文件和FTP文件的存在性),或者至少在关键步骤后检查错误:
On Error Resume Next ' ... 连接和登录代码 ... If Err.Number <> 0 Then Wscript.Echo "登录失败: " & Err.Description Err.Clear Exit Sub End If ' ... 上传代码 ... objFTP.CopyHere objItem, copyType If Err.Number <> 0 Then Wscript.Echo "上传失败: " & Err.Description Err.Clear Exit Sub End If ' 替代固定等待:循环检查FTP上的文件是否存在(简单版) Dim checkCount checkCount = 0 Do While checkCount < 20 ' 最多等20秒,每次等1秒 Wscript.Sleep 1000 On Error Resume Next Set remoteFile = objFTP.ParseName(objItem.Name) If Not remoteFile Is Nothing Then Exit Do End If checkCount = checkCount + 1 Loop If checkCount >= 20 Then Wscript.Echo "上传超时,可能未完成" End If
修改后的完整代码
整合以上所有优化点后的代码:
Set oShell = CreateObject("Shell.Application") Set objFSO = CreateObject("Scripting.FileSystemObject") path = "D:\test\" FTPUpload(path) Sub FTPUpload(path) On Error Resume Next ' 定义CopyHere的静默参数 Const FOF_SILENT = 4 Const FOF_NOCONFIRMATION = 16 Const FOF_NOERRORUI = 1024 Const copyType = FOF_SILENT + FOF_NOCONFIRMATION + FOF_NOERRORUI FTPUser = "xxxxx" FTPPass = "xxxxxx" FTPHost = "xxxx.xxx" FTPDir = "/public_html/testfolder/" ' 1. 连接FTP服务器根目录 strFTP = "ftp://" & FTPHost Set objFTP = oShell.NameSpace(strFTP) If objFTP Is Nothing Then Wscript.Echo "无法连接到FTP服务器: " & FTPHost Exit Sub End If ' 2. 登录FTP objFTP.Items().Parent.Logon FTPUser, FTPPass If Err.Number <> 0 Then Wscript.Echo "FTP登录失败: " & Err.Description Err.Clear Exit Sub End If ' 3. 切换到目标上传目录 Set objFTP = objFTP.Folders.Item(FTPDir) If objFTP Is Nothing Then Wscript.Echo "FTP目标目录不存在: " & FTPDir Exit Sub End If ' 4. 准备要上传的文件 ufile = path & "bappy.txt" If objFSO.FileExists(ufile) Then Set objFile = objFSO.getFile(ufile) strParent = objFile.ParentFolder Set objFolder = oShell.NameSpace(strParent) Set objItem = objFolder.ParseName(objFile.Name) If objItem Is Nothing Then Wscript.Echo "无法获取本地文件: " & ufile Exit Sub End If Wscript.Echo "正在上传文件 " & objItem.Name & " 到 " & strFTP & FTPDir objFTP.CopyHere objItem, copyType If Err.Number <> 0 Then Wscript.Echo "上传失败: " & Err.Description Err.Clear Exit Sub End If ' 5. 等待上传完成(循环检查) Dim checkCount checkCount = 0 Do While checkCount < 20 Wscript.Sleep 1000 Set remoteFile = objFTP.ParseName(objItem.Name) If Not remoteFile Is Nothing Then Wscript.Echo "上传完成!" Exit Do End If checkCount = checkCount + 1 Loop If checkCount >= 20 Then Wscript.Echo "上传超时,请检查服务器状态" End If Else Wscript.Echo "本地文件不存在: " & ufile End If End Sub
额外注意事项
- 确保脚本运行的用户有足够的权限访问本地文件和FTP服务器
- 如果FTP服务器要求被动模式,
Shell.Application默认会使用被动模式,但部分老服务器可能需要主动模式,这时候Shell.Application可能无法支持,只能改用Windows自带的ftp.exe命令行工具(可以用VBScript调用WshShell.Run执行批处理)
内容的提问来源于stack exchange,提问作者elvenza
相关产品推荐
相关产品推荐

