C# 文件同步工具(复制带进度显示)

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace SyncTool
{
    internal class Program
    {
        private static string oldPath = @"";
        private static string newPath = @"";
        static void Main(string[] args)
        {

            if (args.Length == 2)
            {
                oldPath = args[0];
                newPath = args[1];
            }

        GoJob:
            Console.WriteLine("---------------------------------------------");
            Console.WriteLine("------------------文件同步工具---------------");
            Console.WriteLine("---------------------------------------------");

            while (!Directory.Exists(oldPath))
            {
                Console.WriteLine("请输入源始目录");
                oldPath = Console.ReadLine();
            }

            while (!Directory.Exists(newPath))
            {
                Console.WriteLine("请输入目标目录");
                newPath = Console.ReadLine();
            }

            Console.WriteLine("源始目录:" + oldPath);
            Console.WriteLine("目标目录:" + newPath);
            Console.WriteLine("---------------------------------------------");
            Console.WriteLine("请选择你要执行的操作");
            Console.WriteLine("1:开始同步");
            Console.WriteLine("2:检查文件");
            Console.WriteLine("3:更换目录");
            Console.WriteLine("4:清理屏幕");
            Console.WriteLine("5:退出程序");
            Console.WriteLine("---------------------------------------------");
            string key = Console.ReadLine();

            Console.Write("\n你按下的是:" + key + "\r\n");

            if (key == "1")//查询检测
            {
                CopyFile(oldPath);
                Console.WriteLine("----------------------同步完成-----------------------");
                WriteLog("本次复制失败共有:" + errCopyFileList.Count + "个文件\r\n" + string.Join("\r\n", errCopyFileList.ToArray()));
                Console.WriteLine("---------------------------------------------");

                goto GoJob;
            }
            else if (key == "2")//查询检测
            {
                ExistsFile(oldPath);
                Console.WriteLine("----------------------检测完成-----------------------");
                WriteLog("本次检测不存在文件共有:" + noExistsList.Count + "个文件\r\n" + string.Join("\r\n", noExistsList.ToArray()));
                Console.WriteLine("---------------------------------------------");
                WriteLog("本次检测大小不一的文件共有:" + sizeExistsList.Count + "个文件\r\n" + string.Join("\r\n", sizeExistsList.ToArray()));
                Console.WriteLine("---------------------------------------------");
                goto GoJob;
            }
            else if (key == "3")//
            {
                oldPath = "";
                newPath = "";
                goto GoJob;
            }
            else if (key == "4")//
            {
                Console.Clear();
                goto GoJob;
            }
            else if (key == "5")//
            {
                Environment.Exit(0);
                return;
            }

            else
            {
                Console.WriteLine("\n请输入一个有效键!");
                Console.WriteLine("---------------------------------------------");
                goto GoJob;
            }
        }


        #region 归类循环复制文件
        /// <summary>
        /// 复制失败文件
        /// </summary>
        public static List<string> errCopyFileList = new List<string>();

        /// <summary>
        /// 归类循环复制文件
        /// </summary>
        /// <param name="dir"></param>
        public static void CopyFile(string dir)
        {
            if (string.IsNullOrWhiteSpace(dir)) return;
            if (!Directory.Exists(dir)) return;

            foreach (var file in Directory.GetFiles(dir))
            {
                Console.Write(file);
                string newfile = file.Replace(oldPath, newPath);//文件新地址
                string newdir = Path.GetDirectoryName(newfile);
                if (!Directory.Exists(newdir)) Directory.CreateDirectory(newdir);

                FileInfo oldInfo = new FileInfo(file);//旧文件信息
                FileInfo newInfo = new FileInfo(newfile);//新文件信息

                if (!newInfo.Exists)//新文件不存在
                {
                    Console.Write(" 不存在,复制 ");
                    try
                    {
                        CopyFileEx(file, newfile, new CopyProgressRoutine((total, transferred, streamSize, StreamByteTrans, dwStreamNumber, reason, hSourceFile, hDestinationFile, lpData) =>
                        {
                            double percent = Convert.ToDouble(transferred) / Convert.ToDouble(total);
                            string result = percent.ToString("P");//得到6%
                            Console.Write(result);

                            for (int i = 0; i < result.Length; i++)
                            {
                                Console.Write('\u0008');//删除输出的内容
                            }

                            return CopyProgressResult.PROGRESS_CONTINUE;
                        }), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE);

                        Console.Write(" 成功   ");
                    }
                    catch (Exception ex)
                    {
                        if (!errCopyFileList.Contains(file))
                        {
                            errCopyFileList.Add(file);
                        }
                        Console.Write("失败:" + ex.Message);
                    }
                }
                else//新目录存在文件则比对大小
                {
                    Console.Write(" 存在,比大小 ");
                    if (oldInfo.Length != newInfo.Length)//旧目录大小和新目录大小不一样
                    {
                        Console.Write(" " + oldInfo.Length + "-->" + newInfo.Length + " 大小不一,复制 ");
                        try
                        {
                            CopyFileEx(file, newfile, new CopyProgressRoutine((total, transferred, streamSize, StreamByteTrans, dwStreamNumber, reason, hSourceFile, hDestinationFile, lpData) =>
                            {
                                double percent = Convert.ToDouble(transferred) / Convert.ToDouble(total);
                                string result = percent.ToString("P");//得到6%
                                Console.Write(result);

                                for (int i = 0; i < result.Length; i++)
                                {
                                    Console.Write('\u0008');//删除输出的内容
                                }

                                return CopyProgressResult.PROGRESS_CONTINUE;
                            }), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE);

                            Console.Write("成功");
                        }
                        catch (Exception ex)
                        {
                            if (!errCopyFileList.Contains(file))
                            {
                                errCopyFileList.Add(file);
                            }
                            Console.Write("失败:" + ex.Message);
                        }
                    }
                    else//大小一致则跳过
                    {
                        Console.Write(" 一致,跳过 ");
                    }
                }
                Console.WriteLine("");
            }

            foreach (var mydir in Directory.GetDirectories(dir))
            {
                CopyFile(mydir);
            }
        }
        #endregion


        #region Win32_API 复制文件带进度
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName, CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref Int32 pbCancel, CopyFileFlags dwCopyFlags);

        delegate CopyProgressResult CopyProgressRoutine(long TotalFileSize, long TotalBytesTransferred, long StreamSize, long StreamBytesTransferred, uint dwStreamNumber, CopyProgressCallbackReason dwCallbackReason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);

        private static int pbCancel;

        enum CopyProgressResult : uint
        {
            PROGRESS_CONTINUE = 0,
            PROGRESS_CANCEL = 1,
            PROGRESS_STOP = 2,
            PROGRESS_QUIET = 3
        }

        enum CopyProgressCallbackReason : uint
        {
            CALLBACK_CHUNK_FINISHED = 0x00000000,
            CALLBACK_STREAM_SWITCH = 0x00000001
        }

        [Flags]
        enum CopyFileFlags : uint
        {
            COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
            COPY_FILE_RESTARTABLE = 0x00000002,
            COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
            COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
        }
        #endregion

        #region 归类循环复制文件
        /// <summary>
        /// 复制失败文件
        /// </summary>
        public static List<string> noExistsList = new List<string>();
        public static List<string> sizeExistsList = new List<string>();

        /// <summary>
        /// 归类循环检查文件
        /// </summary>
        /// <param name="dir"></param>
        public static void ExistsFile(string dir)
        {
            if (string.IsNullOrWhiteSpace(dir)) return;
            if (!Directory.Exists(dir)) return;

            foreach (var file in Directory.GetFiles(dir))
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(file);
                string newfile = file.Replace(oldPath, newPath);//文件新地址
                string newdir = Path.GetDirectoryName(newfile);
                if (!Directory.Exists(newdir)) Directory.CreateDirectory(newdir);

                FileInfo oldInfo = new FileInfo(file);//旧文件信息
                FileInfo newInfo = new FileInfo(newfile);//新文件信息

                if (!newInfo.Exists)//新文件不存在
                {
                    sb.Append(" 不存在 ");
                    if (!noExistsList.Contains(file))
                    {
                        noExistsList.Add(file);
                    }
                }
                else//新目录存在文件则比对大小
                {
                    sb.Append(" 存在,比大小 ");
                    if (oldInfo.Length != newInfo.Length)//旧目录大小和新目录大小不一样
                    {
                        if (!sizeExistsList.Contains(file))
                        {
                            sizeExistsList.Add(file);
                        }
                        sb.Append(" " + oldInfo.Length + "-->" + newInfo.Length + " 大小不一 ");
                    }
                    else//大小一致则调过
                    {
                        sb.Append(" 一致 ");
                    }
                }
                Console.WriteLine(sb.ToString());
            }

            foreach (var mydir in Directory.GetDirectories(dir))
            {
                ExistsFile(mydir);
            }
        }
        #endregion

        /// <summary>
        /// 输出日志并保存文件
        /// </summary>
        /// <param name="value"></param>
        public static void WriteLog(string value, ConsoleColor color = ConsoleColor.Gray)
        {
            try
            {

                if (string.IsNullOrWhiteSpace(value)) return;
                Console.ForegroundColor = color;
                Console.WriteLine(value);

                string path = DateTime.Now.ToString("yyyy-MM-dd-HH") + ".config";
                StreamWriter streamWriter = new StreamWriter(path, true);
                streamWriter.WriteLine(value);
                streamWriter.Close();
            }
            catch
            {
            }
        }

    }
}

 

posted @ 2022-11-12 22:36  懒人境界  阅读(557)  评论(0编辑  收藏  举报