一、帮助类
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();
///
/// 执行复制函数,线程数如果大于8将按照最多8线程复制
///
/// 源文件全路径
/// 目标文件全路径
/// 是否使用系统缓存,不使用系统缓存的复制速度将远大于使用系统缓存的复制速度
/// 复制线程数
/// true是同步,false是异步
/// 同步等待时间
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();
///
/// 复制文件夹及文件
///
/// 原文件路径
/// 目标文件路径
///
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;
}
}
}
}