1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.IO;
using
System.Threading;
using
Microsoft.Win32.SafeHandles;
using
System.Runtime.InteropServices;
using
System.Media;
using
System.Windows.Forms;
using
System.Runtime.Remoting.Contexts;
using
System.Diagnostics;
namespace
FastCopy
{ 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);
}
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)
{
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)
{
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;
}
} |
相关文章
- 08-10C#/.NET 线程池ThreadPool多线程实现
- 08-10C#读取文件高效方法实现
- 08-10C# 实现一个可取消的多线程操作 示例
- 08-10c#实现用SQL池(多线程),定时批量执行SQL语句 【转】
- 08-10(转).NET 4.5中使用Task.Run和Parallel.For()实现的C# Winform多线程任务及跨线程更新UI控件综合实例
- 08-10C#——await与async实现多线程异步编程
- 08-10C#多线程:使用ReaderWriterLock类实现多用户读/单用户写同步
- 08-10一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器
- 08-10C#基础-FileStream实现多线程断点续传
- 08-10ASP.NET MVC Filters 4种默认过滤器的使用【附示例】 数据库常见死锁原因及处理 .NET源码中的链表 多线程下C#如何保证线程安全? .net实现支付宝在线支付 彻头彻尾理解单例模式与多线程 App.Config详解及读写操作 判断客户端是iOS还是Android,判断是不是在微信浏览器打开