You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下如何用FTP替代RoboCopy同步指定年份文件?

Great question! Moving from RoboCopy to FTP for your photo sync makes sense if you're dealing with slow SMB speeds on your MyCloud. Let's break down how to replicate your exact RoboCopy behavior using PowerShell, with two solid options—one that's robust and easy to use, and another that uses native .NET tools if you can't install third-party software.

WinSCP is a perfect fit here because it natively supports FTP/SFTP, sync logic, file filtering, and multi-threaded transfers—all the core features your RoboCopy command relies on. Here's how to mirror your exact workflow:

Step 1: Set up WinSCP

First, grab the WinSCP .NET Assembly (you can use the portable version if you don't want to install the full app). Extract the WinSCPnet.dll file to a location your script can access (like the same folder as your script).

Step 2: PowerShell Script

This script maps directly to every parameter in your original RoboCopy command:

# Load the WinSCP .NET Assembly
Add-Type -Path "C:\Path\To\WinSCPnet.dll"

# Configure your MyCloud FTP connection details
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Ftp
    HostName = "your-mycloud-ip-or-hostname" # e.g., "192.168.1.100" or "mycloud.local"
    UserName = "your-ftp-username"
    Password = "your-ftp-password"
}

# Match RoboCopy's transfer and filtering rules
$transferOptions = New-Object WinSCP.TransferOptions -Property @{
    # Exclude unwanted file types + filter to 2018 files (replaces /XF, /MAXAGE, /MINAGE)
    FileMask = "*.jpg;*.jpeg;!*.mp4;!*.png;!*.dng;>=2018-01-01 <=2018-12-31"
    # Multi-threaded transfers (matches /MT:32)
    MaxConcurrentTransfers = 32
    # No retries or wait time (matches /R:0 /W:0)
    RetryCount = 0
    # Copy subdirectories including empty ones (matches /S /E)
    TransferMode = [WinSCP.TransferMode]::Binary # Optimal for photo files
}

# Run the sync
try {
    $session = New-Object WinSCP.Session
    $session.Open($sessionOptions)

    # Sync local files to remote (push newer/updated files, matches /XO)
    $syncResult = $session.SynchronizeDirectories(
        [WinSCP.SynchronizationMode]::Remote, # Make remote directory match local
        "D:\OneDrive\Pictures\Camera Roll",
        "/Media/Digital Images/2018/Photos", # Remote FTP path (use forward slashes)
        $false, # Don't delete remote files (RoboCopy doesn't do this by default)
        $false, # Don't mirror (only add/update files)
        [WinSCP.SynchronizationCriteria]::TimeAndSize # Compare files by time + size, like /XO
    )

    # Check for sync errors
    $syncResult.Check()
} finally {
    $session.Dispose()
}

Write-Host "2018 photo sync completed successfully!"

Key Parameter Matches:

  • FileMask: Handles both excluded file types and 2018 date filtering, replacing /XF, /MAXAGE, and /MINAGE
  • MaxConcurrentTransfers: Replicates /MT:32 for multi-threaded transfers
  • RetryCount = 0: Matches /R:0 /W:0 (no retries or wait time)
  • SynchronizeDirectories: Pushes only newer/updated files to the remote, mirroring /XO behavior
  • Subdirectory handling: Automatically copies all subdirectories (including empty ones), matching /S /E

Option 2: Native PowerShell with .NET FtpWebRequest (No Third-Party Tools)

If you can't install WinSCP, you can use .NET's built-in FtpWebRequest, but this requires more manual code to handle directory traversal, filtering, and sync logic. Here's a simplified version that covers your core needs:

# FTP configuration
$ftpHost = "ftp://your-mycloud-ftp-host/"
$remoteRootDir = "Media/Digital Images/2018/Photos"
$localRootDir = "D:\OneDrive\Pictures\Camera Roll"
$ftpUser = "your-ftp-username"
$ftpPass = "your-ftp-password"

# Set up credentials
$credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPass)

# Get all local files matching your 2018 + extension rules
$targetFiles = Get-ChildItem -Path $localRootDir -Recurse -File | Where-Object {
    $_.Extension -notin @(".mp4", ".png", ".dng") -and
    $_.LastWriteTime -ge (Get-Date "2018-01-01") -and
    $_.LastWriteTime -le (Get-Date "2018-12-31")
}

# Helper function to upload files (with /XO-style check)
function Upload-FtpFile {
    param(
        [string]$localPath,
        [string]$remotePath,
        [System.Net.NetworkCredential]$creds
    )

    # Check if remote file exists and is newer than local (skip if so)
    $checkRequest = [System.Net.FtpWebRequest]::Create($remotePath)
    $checkRequest.Credentials = $creds
    $checkRequest.Method = [System.Net.WebRequestMethods+Ftp]::GetDateTimestamp
    try {
        $remoteFileTime = $checkRequest.GetResponse().LastModified
        if ($remoteFileTime -ge (Get-Item $localPath).LastWriteTime) { return }
    } catch {} # Remote file doesn't exist, proceed to upload

    # Upload the file
    $uploadRequest = [System.Net.FtpWebRequest]::Create($remotePath)
    $uploadRequest.Credentials = $creds
    $uploadRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
    $uploadRequest.UseBinary = $true

    $fileStream = [System.IO.File]::OpenRead($localPath)
    $ftpStream = $uploadRequest.GetRequestStream()
    $fileStream.CopyTo($ftpStream)

    $ftpStream.Close()
    $fileStream.Close()
}

# Process each file (add multi-threading with Start-Job if you need /MT:32)
foreach ($file in $targetFiles) {
    # Build remote file path (convert local subdir structure to FTP format)
    $relativePath = $file.FullName.Substring($localRootDir.Length + 1).Replace("\", "/")
    $remoteFilePath = "$ftpHost$remoteRootDir/$relativePath"

    # Create remote subdirectories if they don't exist (matches /E)
    $remoteSubDir = "$ftpHost$remoteRootDir/" + $relativePath.Substring(0, $relativePath.LastIndexOf("/"))
    $dirRequest = [System.Net.FtpWebRequest]::Create($remoteSubDir)
    $dirRequest.Credentials = $credentials
    $dirRequest.Method = [System.Net.WebRequestMethods+Ftp]::MakeDirectory
    try { $dirRequest.GetResponse() } catch {} # Ignore if directory already exists

    # Upload the file
    Upload-FtpFile -localPath $file.FullName -remotePath $remoteFilePath -creds $credentials
}

Write-Host "2018 photo uploads completed!"

Notes on the Native Approach:

  • This script doesn't natively support multi-threading (you'd need to add Start-Job or runspaces to replicate /MT:32, which adds complexity)
  • It manually checks remote file timestamps to match /XO behavior
  • You'll need to handle edge cases like connection drops or permission errors manually (unlike WinSCP's built-in error handling)

Final Recommendation

Stick with the WinSCP option—it's far more maintainable, matches all your RoboCopy parameters out of the box, and handles edge cases like directory creation and connection issues automatically. You can even wrap this script into a batch file if you want to keep the same workflow as your original RoboCopy commands.

内容的提问来源于stack exchange,提问作者Stuart Roberts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:59:30