C# 两个不同文件路径的同步

为了确保路径 A 下的文件和文件夹的结构与路径 B 下保持一致,可以编写一个 C# 程序来递归比较路径 A 和路径 B 中的文件夹和文件,并根据变化来更新路径 B 中的内容。具体来说,代码逻辑需要做到以下几点:

  1. 同步新创建的文件和文件夹:如果 A 中有 B 中没有的文件或文件夹,需要将它们复制到 B 中。
  2. 同步重命名的文件和文件夹:如果 A 中的文件或文件夹被重命名,B 中相应的文件或文件夹也需要进行重命名。
  3. 同步删除的文件和文件夹:如果 A 中的文件或文件夹被删除,B 中相应的文件或文件夹也需要删除。

以下是实现该功能的一个代码示例:

C# 示例代码

using log4net;
using log4net.Config;
using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;

public static class DirectorySync
{
    // 创建一个静态日志实例
    private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    // 获取当前日期前三天的日期
    private static DateTime GetThreeDaysAgoDate()
    {
        return DateTime.Now.AddDays(-3);
    }

    // 计算文件的哈希值(MD5)
    public static string GetFileHash(string filePath)
    {
        using (var md5 = MD5.Create())
        {
            using (var stream = File.OpenRead(filePath))
            {
                return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLowerInvariant();
            }
        }
    }

    public static void SyncDirectories(string sourceDir, string targetDir)
    {
        // 1. 确保源目录存在
        if (!Directory.Exists(sourceDir))
        {
            Log4Helper.Print(1, $"源目录 {sourceDir} 不存在");
            return;
        }

        // 2. 确保目标目录存在
        if (!Directory.Exists(targetDir))
        {
            Directory.CreateDirectory(targetDir);
            Log4Helper.Print(1, $"创建目标 {targetDir} 目录成功");
        }

        // 3. 同步子目录
        foreach (string sourceSubDir in Directory.GetDirectories(sourceDir))
        {
            string dirName = Path.GetFileName(sourceSubDir);
            string targetSubDir = Path.Combine(targetDir, dirName);

            if (!Directory.Exists(targetSubDir))
            {
                Directory.CreateDirectory(targetSubDir);
                Log4Helper.Print(1, $"复制 {targetSubDir} 目录成功");
            }

            // 递归同步子目录
            SyncDirectories(sourceSubDir, targetSubDir);
        }

        // 4. 删除目标目录中多余的子目录
        foreach (string targetSubDir in Directory.GetDirectories(targetDir))
        {
            string dirName = Path.GetFileName(targetSubDir);
            string correspondingSourceSubDir = Path.Combine(sourceDir, dirName);

            if (!Directory.Exists(correspondingSourceSubDir))
            {
                Directory.Delete(targetSubDir, true);
                Log4Helper.Print(1, $"删除目标目录 {targetSubDir} 多余的目录成功");
            }
        }

        // 5. 同步文件
        foreach (string sourceFilePath in Directory.GetFiles(sourceDir))
        {
            string fileName = Path.GetFileName(sourceFilePath);
            string targetFilePath = Path.Combine(targetDir, fileName);

            // 获取文件的最后修改时间
            FileInfo sourceFileInfo = new FileInfo(sourceFilePath);
            DateTime fileLastWriteTime = sourceFileInfo.LastWriteTime;

            // 如果文件在最近三天内修改过
            if (fileLastWriteTime >= GetThreeDaysAgoDate())
            {
                // 如果文件不存在,或者文件的哈希值不同,则进行同步
                if (!File.Exists(targetFilePath) || GetFileHash(sourceFilePath) != GetFileHash(targetFilePath))
                {
                    File.Copy(sourceFilePath, targetFilePath, true);
                    Log4Helper.Print(1, $"复制 {sourceFilePath}{targetFilePath} 目录成功");
                }
            }
        }

        // 6. 删除目标目录中多余的文件
        foreach (string targetFilePath in Directory.GetFiles(targetDir))
        {
            string fileName = Path.GetFileName(targetFilePath);
            string correspondingSourceFilePath = Path.Combine(sourceDir, fileName);

            if (!File.Exists(correspondingSourceFilePath))
            {
                File.Delete(targetFilePath);
                Log4Helper.Print(1, $"删除目标文件 {targetFilePath} 成功");
            }
        }
    }

    static void Main()
    {
        // 初始化 log4net 配置
        XmlConfigurator.Configure(new FileInfo("log4net.config"));

        // 输出日志
        Log4Helper.Print(1, "应用程序启动");

        // 加载配置文件
        XDocument config = XDocument.Load("config.config");

        // 读取源路径和目标路径
        string sourcePath = config.Root.Element("Paths").Element("SourcePath").Value;
        string targetPath = config.Root.Element("Paths").Element("TargetPath").Value;

        // 获取当前日期
        string currentDate = DateTime.Now.ToString("yyyyMMdd"); // 格式为 20241104

        // 拼接源目录
        string sourceDir = Path.Combine(sourcePath, currentDate);
        string targetDir = Path.Combine(targetPath, currentDate);

        // 调用同步函数
        SyncDirectories(sourceDir, targetDir);
    }
}


public static class Log4Helper
    {
        //private Log4Helper() { }
        #region 引用路径

        /// <summary>
        /// 一般信息
        /// </summary>
        private static readonly ILog logInfo = LogManager.GetLogger("LogInfo");

        /// <summary>
        /// 一般警告
        /// </summary>
        private static readonly ILog logWarn = LogManager.GetLogger("LogWarn");

        /// <summary>
        /// 一般错误
        /// </summary>
        private static readonly ILog logError = LogManager.GetLogger("LogError");

        /// <summary>
        /// 致命错误
        /// </summary>
        private static readonly ILog logFatalError = LogManager.GetLogger("LogFatalError");

        /// <summary>
        /// 调试日志
        /// </summary>
        private static readonly ILog logDebug = LogManager.GetLogger("LogDebug");

        /// <summary>
        /// 运行日志
        /// </summary>
        private static readonly ILog logRunOperate = LogManager.GetLogger("LogRunOperate");

        /// <summary>
        /// 数据日志
        /// </summary>
        private static readonly ILog logData = LogManager.GetLogger("LogData");

        #endregion

        #region 一般信息记录
        private static void LogInfo(string str)
        {
            if (logInfo.IsInfoEnabled)
            {
                logInfo.Info(str); // 记录一般信息
            }
        }
        #endregion

        #region 一般警告
        private static void LogWarn(string str)
        {
            if (logWarn.IsWarnEnabled)
            {
                logWarn.Warn(str); // 记录一般警告
            }
        }
        #endregion

        #region 一般错误
        private static void LogError(string str)
        {
            if (logError.IsErrorEnabled)
            {
                logError.Error(str); // 记录一般错误
            }
        }
        #endregion

        #region 致命错误
        private static void LogFatalError(string message, Exception exception)
        {
            if (logFatalError.IsFatalEnabled)
            {
                logFatalError.Fatal(message, exception);
            }
        }

        private static void LogFatalError(string message)
        {
            if (logFatalError.IsFatalEnabled)
            {
                logFatalError.Fatal(message);
            }
        }
        #endregion

        #region 调试日志
        private static void LogDebug(string str)
        {
            if (logDebug.IsDebugEnabled)
            {
                logDebug.Debug(str); // 调试日志
            }
        }
        #endregion

        #region 运行日志
        private static void LogRunLog(string str)
        {
            if (logRunOperate.IsInfoEnabled)
            {
                logRunOperate.Info(str); // 记录运行日志
            }
        }
        #endregion

        #region 数据日志
        private static void LogDataLog(string str)
        {
            if (logData.IsInfoEnabled)
            {
                logData.Info(str); // 记录数据日志
            }
        }
        #endregion

        public static void Print(int level, string message, Exception exception = null)
        {
            switch (level)
            {
                case 1:
                    Log4Helper.LogInfo(message);
                    break;
                case 2:
                    Log4Helper.LogWarn(message);
                    break;
                case 3:
                    Log4Helper.LogError(message);
                    break;
                case 4:
                    if (exception == null)
                    {
                        Log4Helper.LogFatalError(message);
                    }
                    else
                    {
                        Log4Helper.LogFatalError(message, exception);
                    }
                    break;
                case 5:
                    Log4Helper.LogDebug(message);
                    break;
                case 6:
                    Log4Helper.LogRunLog(message);
                    break;
                case 7:
                    Log4Helper.LogDataLog(message);
                    break;
                default:
                    Console.WriteLine("未知的日志等级: " + level);
                    break;
            }
        }

    }

代码说明

  1. 确保目标目录存在

    • 如果目标目录 B 不存在,使用 Directory.CreateDirectory(targetDir) 创建它。
  2. 同步文件夹

    • 遍历源路径 A 的所有子文件夹。
    • 如果目标路径 B 中不存在对应的子文件夹,则创建它。
    • 使用递归方式确保所有层级的子文件夹都得到同步。
  3. 删除目标路径中多余的文件夹

    • 遍历目标路径 B 的所有子文件夹。
    • 如果这些子文件夹在源路径 A 中不存在,则删除它们。
  4. 同步文件

    • 遍历源路径 A 中的所有文件。
    • 如果目标路径 B 中不存在相应的文件,则将源文件复制过去。
    • 如果文件已经存在,但源文件的 LastWriteTime 比目标文件的新,说明源文件有更新,则替换目标文件。
  5. 删除多余的文件

    • 遍历目标路径 B 中的所有文件。
    • 如果这些文件在源路径 A 中不存在,则删除它们。

优化和扩展

  1. 重命名检测

    • 上述代码不会明确处理重命名的情况,它会认为源路径中不存在对应的文件或文件夹,因此删除旧的并重新复制新的。
    • 如果需要保留重命名记录并高效同步,可以考虑使用文件和文件夹的唯一标识(如 ID 或 Hash 值),这超出了简单的同步逻辑,需要更复杂的数据记录和对比机制。
  2. 日志和错误处理

    • 添加日志记录每个文件和文件夹的同步操作,可以方便调试。
    • 添加异常处理,以确保在某些操作失败时不会中断整个同步过程。
  3. 效率提升

    • 对于大型目录结构,频繁的文件遍历和复制操作可能会导致性能问题。可以考虑使用增量同步工具,避免每次都全量遍历。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好玩的Matlab(NCEPU)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值