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/MINAGEMaxConcurrentTransfers: Replicates/MT:32for multi-threaded transfersRetryCount = 0: Matches/R:0 /W:0(no retries or wait time)SynchronizeDirectories: Pushes only newer/updated files to the remote, mirroring/XObehavior- Subdirectory handling: Automatically copies all subdirectories (including empty ones), matching
/S /E
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-Jobor runspaces to replicate/MT:32, which adds complexity) - It manually checks remote file timestamps to match
/XObehavior - You'll need to handle edge cases like connection drops or permission errors manually (unlike WinSCP's built-in error handling)
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

