Windows上的命令行从FTP站点

时间:2016-08-22 10:11:57

标签: batch-file ftp winscp

我需要在Windows上从命令行运行批处理脚本,从FTP站点下载最新文件(有时最新文件可能包含多个文件)。

我使用了WinSCP.com中的以下命令,但我只获得了一个最新文件。可以给我一些指导吗?

get -latest *.txt

Wxample:使用上面的命令我只获得文件名XYZ.txt文件,我希望有一个脚本设法同时获得ABC.txtZZZ.txt

filename        last written date
------------    ----------------------
ABC.txt         2016-01-01
ZZZ.txt         2016-01-01
A123.txt        2015-12-10

2 个答案:

答案 0 :(得分:1)

没有基于日期下载多个文件的内置命令,我们必须手动完成。

标准ls输出是人类可读的,但不按日期排序:

D---------   0                           0 Aug 21 15:32:37 2016 Default

我们需要使用/xmllog=参数

来创建xml日志
<?xml version="1.0" encoding="UTF-8"?>
<session xmlns="........." name="USER@localhost" start="2016-08-23T15:41:10.708Z">
  <ls>
    <destination value="/temp" />
    <files>
      <file>
        <filename value=".." />
        <type value="D" />
        <modification value="1899-12-30T02:00:00.000Z" />
        <permissions value="---------" />
      </file>

好,每个文件都有一个机器可读的日期,名称,类型(目录为D,我们将跳过它们)。

批处理文件。
(评论分隔符也是代码的一部分)

@echo off
  

:设置

setlocal enableDelayedExpansion
set "WinSCP=C:\somepath\WinSCP.com"
set "ftp=ftp://USER:PASSWORD@ftp.server.com"
set "remoteFolder=/someFolderNoTrailingSlash"
  

:列出所有ftp文件

"%WinSCP%" ^
    /command "open %ftp%" "ls ""%remoteFolder%""" "exit" ^
    /xmllog="%temp%\ftplog.xml" >nul
(
    set isDirectory=
    for /f "tokens=1,3 delims=<= " %%a in ('type "%temp%\ftplog.xml"') do (
        if "%%a"=="filename"     (set "line=%%~b" & set isDirectory=)
        if "%%a"=="type" if "%%~b"=="D" (set isDirectory=yes)
        if "%%a"=="modification" if not defined isDirectory (
            set "line=%%~b*!line!"
            echo !line!
        )
    )
) > "%temp%\ftplist.txt"
  

:按日期排序并制作WinSCP脚本以获取具有相同日期的最新文件

set lastDate=
(
    echo open %ftp%
    for /f "delims=* tokens=1,2" %%a in ('
        sort /reverse "%temp%\ftplist.txt"
    ') do (
        for /f "delims=T" %%c in ("%%a") do set thisDate=%%c
        if defined lastDate (
            if not !thisDate!==!lastDate! goto download
        ) else (
            set lastDate=!thisDate!
        )
        echo get -preservetime "%remoteFolder%/%%b"
    )
) > "%temp%\ftpscript.txt"
if not defined lastDate goto cleanup
  

:下载并清理临时文件

:download
"%WinSCP%" /script="%temp%\ftpscript.txt" /command "exit"

:cleanup
del "%temp%\ftplog.xml" "%temp%\ftplist.txt" "%temp%\ftpscript.txt"

pause

答案 1 :(得分:0)

虽然这对于简单的WinSCP脚本和批处理文件是可行的,但正如answer by @wOxxOm所示,使用WinSCP .NET assembly,在PowerShell等更高级的语言中,代码更具可读性。

以下代码部分基于示例Downloading the most recent file

param (
    $session = "ftp://USER:PASSWORD@ftp.server.com",
    $remotePath = "/remote/path",
    $localPath = "C:\local\path"
)

try
{
    Add-Type -Path "WinSCPnet.dll"

    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions
    $sessionOptions.ParseUrl($session)

    try
    {
        Write-Host "Connecting..."
        $session = New-Object WinSCP.Session

        $session.Open($sessionOptions)

        $files = $session.ListDirectory($remotePath).Files

        $latest_file =
            $files |
            Where-Object { -Not $_.IsDirectory } |
            Sort-Object LastWriteTime -Descending |
            Select-Object -First 1

        Write-Host (
            "Latest file is $latest_file created on $($latest_file.LastWriteTime)")

        $day = Get-Date -date $latest_file.LastWriteTime -hour 0 -minute 0 -second 0

        $latest_files =
            $files |
            Where-Object { -Not $_.IsDirectory } |
            Where-Object { $_.LastWriteTime -ge $day }

        Write-Host "Downloading $($latest_files.Count) files created after $day"

        foreach ($file in $latest_files)
        {
            $path = $file.FullName
            Write-Host $path
            $session.GetFiles(
                [WinSCP.RemotePath]::EscapeFileMask($path),
                (Join-Path $localPath $file.Name)).Check()
        }

        Write-Host "Done"
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }

    exit 0
}
catch [Exception]
{
    Write-Host $_.Exception.Message
    exit 1
}