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 { } } } }