一、帮助类
- 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.Copy
- if (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);
- }
- }
- }
-
- }
- }
- else
- throw 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;
- }
- }
- }
- }