WinSCP同步时删除两边文件

WinSCP delete files on both sides when synchronizing

使用 WinSCP,有什么方法可以同步(在 SFTP 和本地目录之间)包括删除吗?

场景如下:如果文件存在于任何一侧而另一侧不存在,则应该创建它(synchronize both 就可以了)。如果某个文件在任一端被删除,则应在另一端将其删除。

我想我需要某种日志来跟踪文件何时被删除,在一侧或另一侧,以便可以在另一侧反映更改边.

如果我是对的,我认为 WinSCP 没有执行此操作的任何命令。有人做过吗?

WinSCP 做不到。它的同步是无状态的。对于您想要做的事情,您确实必须记住目录的先前状态。为了能够决定,是在一侧添加了不匹配的文件,还是在另一侧删除了不匹配的文件。

这对于普通 WinSCP scripting and a batch file. But with WinSCP .NET assembly from a PowerShell script, it is not that difficult. You can use the Session.CompareDirectories method with the "both" mode 来说几乎是不可能的。对于 UploadNewDownloadNew 的差异,在适当的时候将它们自定义为删除(使用缓存文件列表来决定)。

有 WinSCP 扩展 Two-Way Synchronization with Delete with SFTP/FTP server:

try
{
    Add-Type -Path "WinSCPnet.dll"
 
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Sftp
        HostName = "example.com"
        UserName = "user"
        Password = "password"
        SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx...="
    }

    $localPath = "C:\local\path"
    $remotePath = "/remote/path"

    $previousFilesFile = "previous.txt"
    if (Test-Path $previousFilesFile)
    {
        Write-Host "Loading list of previous local files..."
        [string[]]$previousFiles = Get-Content $previousFilesFile
    }
    else
    {
        Write-Host "No list of previous local files"
        $previousFiles = @()
    }

    $session = New-Object WinSCP.Session
 
    try
    {
        # Connect
        Write-Host "Connecting..."
        $session.Open($sessionOptions)

        $differences =
            $session.CompareDirectories(
                [WinSCP.SynchronizationMode]::Both, $localPath, $remotePath, $False)

        if ($differences.Count -eq 0)
        {
            Write-Host "No changes found."   
        }
        else
        {
            Write-Host "Synchronizing $($differences.Count) change(s)..."

            foreach ($difference in $differences)
            {
                $action = $difference.Action
                if ($action -eq [WinSCP.SynchronizationAction]::UploadNew)
                {
                    if ($previousFiles -contains $difference.Local.FileName)
                    {
                        $path = $difference.Local.FileName
                        Write-Host "Removing local file $path..."
                        Remove-Item -Recurse $path
                    }
                    else
                    {
                        Write-Host "Uploading new $($difference.Local.FileName)..."
                        $difference.Resolve($session) | Out-Null
                    }
                }
                elseif ($action -eq [WinSCP.SynchronizationAction]::DownloadNew)
                {
                    $localFilePath =
                        [WinSCP.RemotePath]::TranslateRemotePathToLocal(
                            $difference.Remote.FileName, $remotePath, $localPath)
                    if ($previousFiles -contains $localFilePath)
                    {
                        $path = $difference.Remote.FileName
                        Write-Host "Removing remote file $path..."
                        $path = [WinSCP.RemotePath]::EscapeFileMask($path)
                        $session.RemoveFiles($path).Check()
                    }
                    else
                    {
                        Write-Host "Downloading new $($difference.Remote.FileName)..."
                        $difference.Resolve($session) | Out-Null
                    }
                }
                elseif ($action -eq [WinSCP.SynchronizationAction]::DownloadUpdate)
                {
                    Write-Host "Downloading updated $($difference.Remote.FileName)..."
                    $difference.Resolve($session) | Out-Null
                }
                elseif ($action -eq [WinSCP.SynchronizationAction]::UploadUpdate)
                {
                    Write-Host "Uploading updated $($difference.Local.FileName)..."
                    $difference.Resolve($session) | Out-Null
                }
                else
                {
                    throw "Unexpected difference $action"
                }
            }
        }
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }

    Write-Host "Saving current local file list..."
    $localFiles =
        Get-ChildItem -Recurse -Path $localPath |
        Select-Object -ExpandProperty FullName
    Set-Content $previousFilesFile $localFiles

    Write-Host "Done."
    exit 0
}
catch
{
    Write-Host "Error: $($_.Exception.Message)"
    exit 1
}