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

WinSCP.Net远程到本地复制时文件夹无法正常保留层级同步问题求助

问题根因
  • 本地路径拼接错误:当前仅用 fileInfo.Name 拼接本地存储路径,仅保留了文件名,丢失了远程文件相对于根同步目录的层级结构,导致所有文件都被放到目标根目录下。
  • 目录创建逻辑未生效:你通过正则 \.(dat|err)$ 过滤枚举结果,仅匹配后缀为dat/err的文件,目录不会被匹配到,因此 fileInfo.IsDirectory 的分支永远不会执行,对应子目录不会被提前创建。
  • 重复请求冗余:你在判断文件新旧时重复调用 SFTP_Session.GetFileInfo 获取远程文件时间,实际上 EnumerateRemoteFiles 返回的 RemoteFileInfo 已经自带 LastWriteTime 属性,无需额外请求服务器。
修复方案

直接修改foreach循环内的路径逻辑,提前自动创建父目录即可,不需要单独枚举处理目录:

string sRemotePath = LogRootFolder + "ABCD/outcomes/";
string sLocalFolder = Path.Combine(LocalFolder, @"ABCD\");

if (SFTP_Session.Opened)
{
    using (SFTP_Session)
    {
        SFTP_Session.QueryReceived += (sender, e) =>
        {
            ...
            e.Continue();
        };                                                
        Regex mask = new Regex(@"\.(dat|err)$", RegexOptions.IgnoreCase);
        IEnumerable<RemoteFileInfo> fileInfos =
            SFTP_Session.EnumerateRemoteFiles(sRemotePath, null, EnumerationOptions.AllDirectories)
            .Where(fileInfo => mask.Match(fileInfo.Name).Success)
            .ToList();

        foreach (RemoteFileInfo fileInfo in fileInfos)
        {
            // 计算远程文件相对于同步根目录的相对路径
            string relativePath = fileInfo.FullName.Substring(sRemotePath.Length).TrimStart('/');
            // 转换为Windows路径分隔符
            relativePath = relativePath.Replace('/', Path.DirectorySeparatorChar);
            // 拼接完整本地路径
            string localFilePath = Path.Combine(sLocalFolder, relativePath);

            // 提前创建文件对应的父目录
            string localDir = Path.GetDirectoryName(localFilePath);
            if (!Directory.Exists(localDir))
            {
                Directory.CreateDirectory(localDir);
            }

            bool bDownload = false;
            // 若本地不存在该文件则下载
            if (!File.Exists(localFilePath))
            {
                bDownload = true;
            }
            else    // 若本地文件已存在但比远程文件旧则下载,否则跳过
            {
                // 直接使用枚举返回的时间属性,无需额外请求服务器
                DateTime remoteWriteTime = fileInfo.LastWriteTime;
                DateTime localWriteTime = File.GetLastWriteTime(localFilePath);

                if (remoteWriteTime > localWriteTime)
                {
                    bDownload = true;
                }
                else
                {
                    bDownload = false;
                }
            }

            if (bDownload)
            {
                // 下载文件
                TransferOptions oTrRes = new TransferOptions();
                oTrRes.TransferMode = TransferMode.Automatic;
                oTrRes.FilePermissions = null;
                oTrRes.PreserveTimestamp = false;
                oTrRes.ResumeSupport.State = TransferResumeSupportState.Off;
                string remoteFilePath = RemotePath.EscapeFileMask(fileInfo.FullName);
                TransferOperationResult transferResult = SFTP_Session.GetFiles(remoteFilePath, localFilePath, false, oTrRes);
                                
                // 出现任意错误则抛出
                transferResult.Check();

                foreach (TransferEventArgs transfer in transferResult.Transfers)
                {
                    // 将本地文件信息存入数据表供后续处理
                    ...
                }
                SessionRemoteExceptionCollection srec = transferResult.Failures;

                foreach (SessionRemoteException sre in srec)
                {
                    // 记录错误日志
                }

                // 判断下载是否成功
                if (!transferResult.IsSuccess)
                {
                    // 记录错误日志(继续处理其他文件)
                }
            }
        }
    }
}

修改后远程文件会完整保留层级结构存储到本地,例如远程路径/xyz/gtc/a00/ABCD/outcomes/backup/2021-06-23/a.dat会自动存储到本地路径Z:\My_Data\ABCD\backup\2021-06-23\a.dat。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 16:54:01