最近在旧项目升级中遇到一个问题。把它记录下来,以便日后查看。本人新手,其中不足还需高手指点,解答小z的疑问。
疑问:在Window7中测试直接拷贝文件在250项/秒左右。但是在通过程序中控制线程数量,并且通过分配线程的任务来拷贝,始终速度都没有达到理想值。
问题:旧项目在存放图片附件是分别存放在DownFile 、UpFile 两个文件夹内(分为两类文件),系统运行时间一久,里面文件也越来越多,管理起来非常麻烦。每次在打开这两个文件夹总是无响应。
新项目需求:这两类文件分别是月为单位存放在文件夹内,文件名保持不变,文件根路径格式/DownFile/yyMM。通过写一个小程序来拷出图片附件。
旧目录DownFile中存放的文件命名规则是:(DateTime.Now.Ticks)+扩展名 。
目录UpFile中文件命名规则是:(大写"R" + yyMMddhhmmssfff) + 扩展名。
根据文件名字中提取年月来决定存放路径。现将拷贝文件的方式在代码中展示。
程序配置文件:app.config
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings> <!--线程数量--> <add key="ThreadCount" value="8" /> <!--文件源路径 DownFile;UpFile--> <add key="SourceDir" value="C:\Users\Administrator\Desktop\DownFile;C:\Users\Administrator\Desktop\UpFile" /> <!--目标存放路径--> <add key="ToDir" value="C:\Users\Administrator\Documents\Visual Studio 2008\Projects\ThreadCopyFile\CopyFileToDirectory\bin\Debug\CopyFolder" /> </appSettings> </configuration>
扫描二维码关注公众号,回复:
142261 查看本文章
代码文件:ThreadCopyFile2.cs
/// <summary> /// 多线程-参数类 /// </summary> public class SplitArr { public int thread_id { get; set; } public int start_index { get; set; } public int end_index { get; set; } }
/// <summary> /// 多线程文件拷贝 /// </summary> public class ThreadCopyFile2 { #region 属性 private List<Thread> threadList = new List<Thread>();//线程列表 private event EventHandler OnNumberClear;//任务执行完成引发的事件 private Stopwatch sw = new Stopwatch();//时间计数 private int counter = 1;//处理任务的个数 private List<string> stringList;//文件列表 private int total = 0;//文件总个数 #endregion /// <summary> /// 程序入口 /// </summary> public static void Main() { ThreadCopyFile2 tcf = new ThreadCopyFile2(); tcf.StartWrok(); } #region 线程工作内容 /// <summary> /// 初始化-并启动工作线程 /// </summary> public ThreadCopyFile2() { //加载文件列表 InitFileList(); //初始进度条 ProcessBarInit(); int ThreadCount = Convert.ToInt32(ConfigurationManager.AppSettings["ThreadCount"]); //设置线程工作范围 Dictionary<int, int[]> root = Splice(stringList, ThreadCount); //设置线程 for (int i = 0; i < ThreadCount; i++) { Thread thread = new Thread(new ParameterizedThreadStart(CopyFile)); thread.Name = i.ToString();//设置线程ID //线程工作范围 SplitArr sa = new SplitArr(); sa.thread_id = i; sa.start_index = root[i][0]; sa.end_index = root[i][1]; thread.Start(sa);//启动线程 threadList.Add(thread); } //线程完成执行事件 OnNumberClear += new EventHandler(CompleteEvent); } /// <summary> /// 加载文件列表 /// </summary> private void InitFileList() { var SourceDir = ConfigurationManager.AppSettings["SourceDir"]; string[] path = SourceDir.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); //获取文件列表 stringList = new List<string>(); stringList.AddRange(Directory.GetFiles(path[0]).Where<string>(f => CheckExtion(f))); stringList.AddRange(Directory.GetFiles(path[1]).Where<string>(f => CheckExtion(f))); total = stringList.Count;//文件总个数 } /// <summary> /// 开始工作 /// </summary> public void StartWrok() { //计时器-开始工作 sw.Start(); } /// <summary> /// 线程锁 /// </summary> readonly object obj = new object(); /// <summary> /// 文件拷贝 /// </summary> private void CopyFile(object _SplitArr) { SplitArr sa = _SplitArr as SplitArr; if (sa != null) { var ToDir = ConfigurationManager.AppSettings["ToDir"]; string newPath = String.Empty;//新路径 string newFilePath = String.Empty;//文件新全路径 FileInfo fi; int rate; //Console.WriteLine("ID:" + sa.thread_id + "\tsa.start_index:" + sa.start_index + "\tsa.end_index:" + sa.end_index); int tempNum = sa.start_index; while (tempNum <= sa.end_index) { string oldFilePath = stringList[tempNum]; fi = new FileInfo(oldFilePath); //根据Source文件上一级路径做条件,返回相应新的存放路径 newPath = Path.Combine(ToDir, Path.Combine(fi.Directory.Name, AnalysisName(fi.Name, fi.Directory.Name))); newFilePath = Path.Combine(newPath, fi.Name); //判断新路径是否存在 if (!Directory.Exists(newPath)) { Directory.CreateDirectory(newPath); } //判断目标路径是否存在该文件 if (!File.Exists(newFilePath) && File.Exists(fi.FullName)) { File.Copy(fi.FullName, newFilePath); ////删除ArrayList中的元素 //stringList.RemoveAt(0); //stringList.TrimExcess(); //累加任务数 counter++; //判断是否处理完任务 if (stringList.Count == counter) { OnNumberClear(this, new EventArgs());//引发完成事件 } //计算百分比 rate = CalcRate(counter); //标题设置 Console.Title = "正在拷贝第【" + counter.ToString() + "】个文件;进度" + rate.ToString() + "%"; //设置进度条 SetProcessBar(rate - 1); //等待 Thread.Sleep(1); } tempNum++; } } } /// <summary> /// 执行完成执行的事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void CompleteEvent(object sender, EventArgs e) { sw.Stop(); Console.SetCursorPosition(0, 7); Console.Write("执行完成,停止了所有线程的执行。成功拷贝文件:" + total.ToString() + "个,用时:" + sw.ElapsedMilliseconds.ToString() + "毫秒"); Console.Title = "成功拷贝文件【" + total.ToString() + "】个"; foreach (Thread thread in threadList) { thread.Abort(); } } #endregion #region 公共函数 /// <summary> /// 文件类型检查 /// </summary> /// <param name="ext"></param> /// <returns></returns> bool CheckExtion(string ext) { return ext.EndsWith(".bmp") || ext.EndsWith(".jpg") || ext.EndsWith(".jpeg") || ext.EndsWith(".png") || ext.EndsWith(".gif") || ext.EndsWith(".tif"); } /// <summary> /// 根据文件名分析存放路径 /// </summary> /// <param name="fileName"></param> /// <param name="flag"></param> /// <returns></returns> string AnalysisName(string fileName, string flag) { switch (flag)//根据标识判断要返回的路径 { case "DownFile": string name1 = Regex.Match(fileName, "\\d*(?=\\.)").Value; var time = new DateTime(Convert.ToInt64(name1)); return time.ToString("yyMM"); case "UpFile": return Regex.Match(fileName, "(?<=R)\\d{4}").Groups[0].Value; default: return ""; } } /// <summary> /// 分割集合 /// </summary> /// <param name="oldStr">要分割的字符串</param> /// <param name="length">分割后次数</param> /// <returns></returns> private static Dictionary<int, int[]> Splice(List<string> oldArray, int length) { Dictionary<int, int[]> root = new Dictionary<int, int[]>(); int count = oldArray.Count; if (count > length) { int num = count / length; int last = count % length;//剩余的元素个数 bool temp = false; if (last > 0) { num++; temp = true; } int tempNum = 0; for (int i = 1; i <= length; i++) { if ((i - 1) == 0) { int rst = (temp ? num - 1 : num) - 1; root.Add(i - 1, new int[] { 0, rst }); tempNum = rst + 1; } else if (i == length) { root.Add(i - 1, new int[] { tempNum, count - 1 }); } else { int rst = root[0][1] * i + 1; root.Add(i - 1, new int[] { tempNum, rst }); tempNum = rst; } } } else { root.Add(0, new int[] { length }); } return root; } #endregion #region 进度条 /// <summary> /// 初始化进度条 /// </summary> void ProcessBarInit() { Console.WriteLine("\n************************工作进度************************\n"); Console.Write(" "); Console.BackgroundColor = ConsoleColor.Gray; for (int i = 1; i <= 50; i++) { Console.Write(" "); } Console.BackgroundColor = ConsoleColor.Black; Console.Write(""); Console.SetCursorPosition(0, 4); Console.Write("\n********************************************************\n"); } /// <summary> /// 设置进度 /// </summary> /// <param name="position"></param> void SetProcessBar(int position) { Monitor.Enter(obj); //绘制进度条进度 Console.BackgroundColor = ConsoleColor.Green;//设置进度条颜色 Console.SetCursorPosition(position / 2 + 1, 3);//设置光标位置,参数为第几列和第几行 Console.Write(" ");//移动进度条 Console.BackgroundColor = ConsoleColor.Black;//恢复输出颜色 Console.SetCursorPosition(52, 3);//设置光标位置,参数为第几列和第几行 Console.Write((position + 1).ToString() + "%");//移动进度条 Monitor.Exit(obj); } /// <summary> /// 计算百分比 /// </summary> /// <param name="count"></param> /// <returns></returns> int CalcRate(int count) { int result = Convert.ToInt32((float)count / (float)total * 100); return result; } #endregion }