一、帮助类
using System;
using System.IO;
using System.Threading;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Diagnostics;namespace FastCopyClass
{public class FastCopy{private const short FILE_ATTRIBUTE_NORMAL = 0x80;private const short INVALID_HANDLE_VALUE = -1;private const uint GENERIC_READ = 0x80000000;private const uint GENERIC_WRITE = 0x40000000;private const uint CREATE_NEW = 1;private const uint CREATE_ALWAYS = 2;private const uint OPEN_EXISTING = 3;private const uint FILE_FLAG_NO_BUFFERING = 0x20000000;private const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;private const uint FILE_SHARE_READ = 0x00000001;private const uint FILE_SHARE_WRITE = 0x00000002;[DllImport("kernel32.dll", SetLastError = true)]static extern SafeFileHandle CreateFile(string IpFileName, uint dwDesiredAccess,uint dwShareMode, IntPtr IpSecurityAttributes, uint dwCreationDisposition,uint dwFlagsAndAttributes, IntPtr hTemplateFile);private int _ThreadNum;private Thread[] CopyThread;private long ReadBufferSize = 1024 * 1024 * 16;public long TotalReadCount = 0;public long AverageCopySpeed;public int ProgressBarValue = 0;private DateTime start;private FileInfo SourceFileInfo;private string _DestFileName;private string _SourceFileName;private bool _IsUsingSystemBuff;public delegate void CopyFinished(string IsFinish);private bool[] isfirst;public event CopyFinished CopyF;private bool WaitingEnd = true;private DateTime WaitTime;private int ThreadExitCout = 0;private object ThreadLock = new object();/// <summary>/// 执行复制函数,线程数如果大于8将按照最多8线程复制/// </summary>/// <param name="SourceFileName">源文件全路径</param>/// <param name="DestFileName">目标文件全路径</param>/// <param name="IsUsingSystemBuff">是否使用系统缓存,不使用系统缓存的复制速度将远大于使用系统缓存的复制速度</param>/// <param name="ThreadNum">复制线程数</param>/// <param name="IsSynchronous">true是同步,false是异步</param>/// <param name="WaitMilliseconds">同步等待时间</param>public void ExeCopy(string SourceFileName, string DestFileName, bool IsUsingSystemBuff, int ThreadNum, bool IsSynchronous, double WaitMilliseconds){//Console.WriteLine("开始时间:" + DateTime.Now.ToString("hh:mm:ss"));try{SourceFileInfo = new FileInfo(SourceFileName);_DestFileName = DestFileName;_SourceFileName = SourceFileName;_IsUsingSystemBuff = IsUsingSystemBuff;//if (SourceFileInfo.Exists)//{//小文件使用系统复制File.Copyif (SourceFileInfo.Length > 0 && SourceFileInfo.Length < 100 * 1024 * 1024){File.Copy(SourceFileName, DestFileName,true);}else//大于100M文件才使用FastCopy{if (ThreadNum > 0){//建立于源文件同样大小的目标空文件if (initFile(SourceFileName, DestFileName))//如果建立或者覆盖文件成功{//打开目标文件//线程数量限制ThreadNum = ThreadNum > 8 ? 8 : ThreadNum;_ThreadNum = ThreadNum;CopyThread = new Thread[ThreadNum];isfirst = new bool[ThreadNum];if (ThreadNum == 1)//执行单线程复制{ThreadParams threadParam = new ThreadParams();threadParam.StartPosition = 0;threadParam.ReadLength = SourceFileInfo.Length;threadParam.start = DateTime.Now;CopyThread[0] = new Thread(new ParameterizedThreadStart(ExeThreadCopy));CopyThread[0].Start(threadParam);}else//执行多线程复制{long parts = (long)_ThreadNum;long StartPosition = 0;long len = SourceFileInfo.Length;long last = SourceFileInfo.Length % parts;len = len - last;long PartLength = len / parts;PartLength = PartLength - PartLength % 512;last = SourceFileInfo.Length - parts * PartLength;start = DateTime.Now;//记录开始时间for (int i = 0; i < ThreadNum; i++){CopyThread[i] = new Thread(new ParameterizedThreadStart(ExeThreadCopy));CopyThread[i].Name = i.ToString();if (i == ThreadNum - 1){ThreadParams threadParam = new ThreadParams();threadParam.StartPosition = StartPosition;threadParam.ReadLength = PartLength + last;threadParam.start = start;CopyThread[i].Start(threadParam);}else{ThreadParams threadParam = new ThreadParams();threadParam.StartPosition = StartPosition;threadParam.ReadLength = PartLength;StartPosition += PartLength;threadParam.start = start;CopyThread[i].Start(threadParam);}}}}}elsethrow new Exception("线程数不能小于1");}//}//else// throw new Exception("打开源文件失败!");//等待线程结束if (IsSynchronous){WaitTime = DateTime.Now;WaitForEnd(WaitMilliseconds);}}catch (Exception ex){PubLibrary.WriteErrLog(ex.ToString());throw ex;}//Console.WriteLine("结束时间:" + DateTime.Now.ToString("hh:mm:ss"));}private void WaitForEnd(double WaitMilliseconds){while (ThreadExitCout < _ThreadNum){Thread.Sleep(100);TimeSpan ts = DateTime.Now.Subtract(WaitTime);if (ts.TotalMilliseconds > WaitMilliseconds){throw new Exception("文件拷贝超时异常");break;}}}private bool initFile(string SourceFileName, string DestFileName){try{FileInfo SourceFileInfo = new FileInfo(SourceFileName);FileInfo DestFileInfo = new FileInfo(DestFileName);if (DestFileInfo.Exists){DestFileInfo.Delete();}Process p = new Process();p.StartInfo.FileName = "fsutil";p.StartInfo.Arguments = "file createnew " + DestFileName + " " + SourceFileInfo.Length.ToString();p.StartInfo.UseShellExecute = false;p.StartInfo.RedirectStandardOutput = true;p.StartInfo.RedirectStandardError = true;p.StartInfo.CreateNoWindow = true;p.Start();p.WaitForExit(1000 * 60 * 2);return true;}catch (Exception ex){PubLibrary.WriteErrLog(ex.ToString());throw ex;}}private void ExeThreadCopy(object obj){ThreadParams param = (ThreadParams)obj;SafeFileHandle SafeFile_SourceFile = CreateFile(_SourceFileName, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero,OPEN_EXISTING, _IsUsingSystemBuff ? 0 : FILE_FLAG_NO_BUFFERING, IntPtr.Zero);SafeFileHandle SafeFile_DestFile = CreateFile(_DestFileName, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero,OPEN_EXISTING, _IsUsingSystemBuff ? 0 : (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH), IntPtr.Zero);FileStream SourceFileStream = new FileStream(SafeFile_SourceFile, FileAccess.Read);FileStream DestFileStream = new FileStream(SafeFile_DestFile, FileAccess.Write);if (param.StartPosition != 0){SourceFileStream.Seek(param.StartPosition, SeekOrigin.Begin);DestFileStream.Seek(param.StartPosition, SeekOrigin.Begin);}BinaryReader SourceFileReader = new BinaryReader(SourceFileStream);BinaryWriter DestFileWriter = new BinaryWriter(DestFileStream);long ThreadTotalReadCount = 0;long ThreadOneTimeReadCount = 0;long ReadCount = 0;bool IsEndPart = false;byte[] ReadBuff = new byte[ReadBufferSize];int ThreadName = int.Parse(Thread.CurrentThread.Name);while (ThreadTotalReadCount < param.ReadLength){//计算每次应该读取流的长度,因为在每部分的最后一点不一定是ReadBufferSize大小?如果不设置流的读取长度,有可能在每部分最后一次读取越界。读到下一部分的内容。Console.WriteLine(Thread.CurrentThread.Name);ReadCount = param.ReadLength - ThreadTotalReadCount < ReadBufferSize ? param.ReadLength - ThreadTotalReadCount : ReadBufferSize;if (ReadCount % 512 == 0)//不是最后一部分的最后一点{IsEndPart = false;}else{IsEndPart = true;}if (IsEndPart){FileStream SourceFileLastStream = new FileStream(_SourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read);FileStream DestFileLastStream = new FileStream(_DestFileName, FileMode.Open, FileAccess.Write, FileShare.Write);BinaryReader SourceFileReadLast = new BinaryReader(SourceFileLastStream);BinaryWriter DestFileWriteLast = new BinaryWriter(DestFileLastStream);SourceFileLastStream.Seek(SourceFileStream.Position, SeekOrigin.Begin);DestFileLastStream.Seek(DestFileStream.Position, SeekOrigin.Begin);byte[] LastBuff = new byte[ReadCount];ThreadOneTimeReadCount = SourceFileReadLast.Read(LastBuff, 0, (int)ReadCount);DestFileWriteLast.Write(LastBuff, 0, (int)ReadCount);try{SourceFileReadLast.Close();}catch { }try{DestFileWriteLast.Close();}catch { }try{SourceFileLastStream.Close();}catch { }try{DestFileLastStream.Close();}catch { }if (CopyF != null){CopyF("复制完成");}}else{ThreadOneTimeReadCount = SourceFileReader.Read(ReadBuff, 0, (int)ReadCount);DestFileWriter.Write(ReadBuff, 0, (int)ReadCount);}TotalReadCount += ThreadOneTimeReadCount;ThreadTotalReadCount += ThreadOneTimeReadCount;TimeSpan ts = DateTime.Now.Subtract(param.start);AverageCopySpeed = TotalReadCount / (long)ts.TotalMilliseconds * 1000 / (1024 * 1024);ProgressBarValue = (int)(TotalReadCount * 100 / SourceFileInfo.Length);WaitTime = DateTime.Now;}try{SourceFileReader.Close();}catch { };try{DestFileWriter.Close();}catch { };try{SourceFileStream.Close();}catch { };try{DestFileStream.Close();}catch { };try{SafeFile_SourceFile.Close();}catch { };try{SafeFile_DestFile.Close();}catch { };lock (ThreadLock){ThreadExitCout += 1;}}private void ExcNormalCopy(object obj){ThreadParams param = (ThreadParams)obj;FileStream SourceFileStream = new FileStream(_SourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read);FileStream DestFileStream = new FileStream(_DestFileName, FileMode.Open, FileAccess.Write, FileShare.Write);BinaryReader SourceFileReader = new BinaryReader(SourceFileStream);BinaryWriter DestFileWriter = new BinaryWriter(DestFileStream);SourceFileStream.Seek(param.StartPosition, SeekOrigin.Begin);DestFileStream.Seek(param.StartPosition, SeekOrigin.Begin);long ThreadTotalReadCount = 0;long ThreadOneTimeReadCount = 0;long ReadCount = 0;byte[] buff = new byte[ReadBufferSize];while (TotalReadCount < param.ReadLength){ReadCount = param.ReadLength - ThreadTotalReadCount >= ReadBufferSize ? ReadBufferSize : param.ReadLength - ThreadTotalReadCount;ThreadOneTimeReadCount = SourceFileReader.Read(buff, 0, (int)ReadCount);DestFileWriter.Write(buff, 0, (int)ReadCount);TimeSpan ts = DateTime.Now.Subtract(param.start);TotalReadCount += ThreadOneTimeReadCount;ThreadTotalReadCount += ThreadOneTimeReadCount;AverageCopySpeed = TotalReadCount / (long)ts.TotalMilliseconds * 1000 / (1024 * 1024);ProgressBarValue = (int)(TotalReadCount * 100 / SourceFileInfo.Length);}SourceFileReader.Close();DestFileWriter.Close();SourceFileStream.Close();DestFileStream.Close();}public void AbortAllThread(){for (int i = 0; i < _ThreadNum; i++){if (CopyThread[i].IsAlive){CopyThread[i].Abort();}}}}public class ThreadParams{public long StartPosition;public long ReadLength;public DateTime start;}
}
二、使用
using System;
using FastCopyClass;namespace FileUploadClass
{public class FileUpload{private static FastCopy fc = new FastCopy();/// <summary>/// 复制文件夹及文件/// </summary>/// <param name="sourceFolder">原文件路径</param>/// <param name="destFolder">目标文件路径</param>/// <returns></returns>public static bool CopyFolder(string sourceFolder, string destFolder){try{PubLibrary.WriteErrLog("复制文件开始:" + DateTime.Now.ToString("yyyy-MM/dd HH:mm:ss"));string folderName = System.IO.Path.GetFileName(sourceFolder);string destfolderdir = System.IO.Path.Combine(destFolder, folderName);string[] filenames = System.IO.Directory.GetFileSystemEntries(sourceFolder);foreach (string file in filenames)// 遍历所有的文件和目录{if (System.IO.Directory.Exists(file)){string currentdir = System.IO.Path.Combine(destfolderdir, System.IO.Path.GetFileName(file));if (!System.IO.Directory.Exists(currentdir)){System.IO.Directory.CreateDirectory(currentdir);}CopyFolder(file, destfolderdir);}else{string srcfileName = System.IO.Path.Combine(destfolderdir, System.IO.Path.GetFileName(file));if (!System.IO.Directory.Exists(destfolderdir)){System.IO.Directory.CreateDirectory(destfolderdir);}fc.ExeCopy(file,srcfileName,false,8,false,30 * 60 * 60 * 1000);//System.IO.File.Copy(file, srcfileName,true);}}PubLibrary.WriteErrLog("复制文件结束:" + DateTime.Now.ToString("yyyy-MM/dd HH:mm:ss"));return true;}catch (Exception ex){PubLibrary.WriteErrLog("复制粘贴文件夹:" + ex.ToString());return false;}}}
}