root / trunk / hammock / src / net35 / ICSharpCode.SharpZipLib.Silverlight / Core / FileSystemScanner.cs @ 0eea575a
History | View | Annotate | Download (17.6 kB)
1 |
// FileSystemScanner.cs |
---|---|
2 |
// |
3 |
// Copyright 2005 John Reilly |
4 |
// |
5 |
// This program is free software; you can redistribute it and/or |
6 |
// modify it under the terms of the GNU General Public License |
7 |
// as published by the Free Software Foundation; either version 2 |
8 |
// of the License, or (at your option) any later version. |
9 |
// |
10 |
// This program is distributed in the hope that it will be useful, |
11 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
// GNU General Public License for more details. |
14 |
// |
15 |
// You should have received a copy of the GNU General Public License |
16 |
// along with this program; if not, write to the Free Software |
17 |
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 |
// |
19 |
// Linking this library statically or dynamically with other modules is |
20 |
// making a combined work based on this library. Thus, the terms and |
21 |
// conditions of the GNU General Public License cover the whole |
22 |
// combination. |
23 |
// |
24 |
// As a special exception, the copyright holders of this library give you |
25 |
// permission to link this library with independent modules to produce an |
26 |
// executable, regardless of the license terms of these independent |
27 |
// modules, and to copy and distribute the resulting executable under |
28 |
// terms of your choice, provided that you also meet, for each linked |
29 |
// independent module, the terms and conditions of the license of that |
30 |
// module. An independent module is a module which is not derived from |
31 |
// or based on this library. If you modify this library, you may extend |
32 |
// this exception to your version of the library, but you are not |
33 |
// obligated to do so. If you do not wish to do so, delete this |
34 |
// exception statement from your version. |
35 |
|
36 |
|
37 |
using System; |
38 |
using System.IO; |
39 |
using System.Linq; |
40 |
|
41 |
namespace ICSharpCode.SharpZipLib.Silverlight.Core |
42 |
{ |
43 |
/// <summary> |
44 |
/// Event arguments for scanning. |
45 |
/// </summary> |
46 |
public class ScanEventArgs : EventArgs |
47 |
{ |
48 |
#region Constructors |
49 |
|
50 |
/// <summary> |
51 |
/// Initialise a new instance of <see cref="ScanEventArgs"/> |
52 |
/// </summary> |
53 |
/// <param name="name">The file or directory name.</param> |
54 |
public ScanEventArgs(string name) |
55 |
{ |
56 |
name_ = name; |
57 |
} |
58 |
|
59 |
#endregion |
60 |
|
61 |
/// <summary> |
62 |
/// The fie or directory name for this event. |
63 |
/// </summary> |
64 |
public string Name |
65 |
{ |
66 |
get { return name_; } |
67 |
} |
68 |
|
69 |
/// <summary> |
70 |
/// Get set a value indicating if scanning should continue or not. |
71 |
/// </summary> |
72 |
public bool ContinueRunning |
73 |
{ |
74 |
get { return continueRunning_; } |
75 |
set { continueRunning_ = value; } |
76 |
} |
77 |
|
78 |
#region Instance Fields |
79 |
|
80 |
private readonly string name_; |
81 |
private bool continueRunning_ = true; |
82 |
|
83 |
#endregion |
84 |
} |
85 |
|
86 |
/// <summary> |
87 |
/// Event arguments during processing of a single file or directory. |
88 |
/// </summary> |
89 |
public class ProgressEventArgs : EventArgs |
90 |
{ |
91 |
#region Constructors |
92 |
|
93 |
/// <summary> |
94 |
/// Initialise a new instance of <see cref="ScanEventArgs"/> |
95 |
/// </summary> |
96 |
/// <param name="name">The file or directory name if known.</param> |
97 |
/// <param name="processed">The number of bytes processed so far</param> |
98 |
/// <param name="target">The total number of bytes to process, 0 if not known</param> |
99 |
public ProgressEventArgs(string name, long processed, long target) |
100 |
{ |
101 |
name_ = name; |
102 |
processed_ = processed; |
103 |
target_ = target; |
104 |
} |
105 |
|
106 |
#endregion |
107 |
|
108 |
/// <summary> |
109 |
/// The name for this event if known. |
110 |
/// </summary> |
111 |
public string Name |
112 |
{ |
113 |
get { return name_; } |
114 |
} |
115 |
|
116 |
/// <summary> |
117 |
/// Get set a value indicating wether scanning should continue or not. |
118 |
/// </summary> |
119 |
public bool ContinueRunning |
120 |
{ |
121 |
get { return continueRunning_; } |
122 |
set { continueRunning_ = value; } |
123 |
} |
124 |
|
125 |
/// <summary> |
126 |
/// Get a percentage representing how much of the <see cref="Target"></see> has been processed |
127 |
/// </summary> |
128 |
/// <value>0.0 to 100.0 percent; 0 if target is not known.</value> |
129 |
public float PercentComplete |
130 |
{ |
131 |
get |
132 |
{ |
133 |
if (target_ <= 0) |
134 |
{ |
135 |
return 0; |
136 |
} |
137 |
return (processed_/(float) target_)*100.0f; |
138 |
} |
139 |
} |
140 |
|
141 |
/// <summary> |
142 |
/// The number of bytes processed so far |
143 |
/// </summary> |
144 |
public long Processed |
145 |
{ |
146 |
get { return processed_; } |
147 |
} |
148 |
|
149 |
/// <summary> |
150 |
/// The number of bytes to process. |
151 |
/// </summary> |
152 |
/// <remarks>Target may be 0 or negative if the value isnt known.</remarks> |
153 |
public long Target |
154 |
{ |
155 |
get { return target_; } |
156 |
} |
157 |
|
158 |
#region Instance Fields |
159 |
|
160 |
private readonly string name_; |
161 |
private readonly long processed_; |
162 |
private readonly long target_; |
163 |
private bool continueRunning_ = true; |
164 |
|
165 |
#endregion |
166 |
} |
167 |
|
168 |
/// <summary> |
169 |
/// Event arguments for directories. |
170 |
/// </summary> |
171 |
public class DirectoryEventArgs : ScanEventArgs |
172 |
{ |
173 |
#region Constructors |
174 |
|
175 |
/// <summary> |
176 |
/// Initialize an instance of <see cref="DirectoryEventArgs"></see>. |
177 |
/// </summary> |
178 |
/// <param name="name">The name for this directory.</param> |
179 |
/// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</param> |
180 |
public DirectoryEventArgs(string name, bool hasMatchingFiles) |
181 |
: base(name) |
182 |
{ |
183 |
hasMatchingFiles_ = hasMatchingFiles; |
184 |
} |
185 |
|
186 |
#endregion |
187 |
|
188 |
/// <summary> |
189 |
/// Get a value indicating if the directory contains any matching files or not. |
190 |
/// </summary> |
191 |
public bool HasMatchingFiles |
192 |
{ |
193 |
get { return hasMatchingFiles_; } |
194 |
} |
195 |
|
196 |
#region Instance Fields |
197 |
|
198 |
private readonly bool hasMatchingFiles_; |
199 |
|
200 |
#endregion |
201 |
} |
202 |
|
203 |
/// <summary> |
204 |
/// Arguments passed when scan failures are detected. |
205 |
/// </summary> |
206 |
public class ScanFailureEventArgs |
207 |
{ |
208 |
#region Constructors |
209 |
|
210 |
/// <summary> |
211 |
/// Initialise a new instance of <see cref="ScanFailureEventArgs"></see> |
212 |
/// </summary> |
213 |
/// <param name="name">The name to apply.</param> |
214 |
/// <param name="e">The exception to use.</param> |
215 |
public ScanFailureEventArgs(string name, Exception e) |
216 |
{ |
217 |
name_ = name; |
218 |
exception_ = e; |
219 |
ContinueRunning = true; |
220 |
} |
221 |
|
222 |
#endregion |
223 |
|
224 |
/// <summary> |
225 |
/// The applicable name. |
226 |
/// </summary> |
227 |
public string Name |
228 |
{ |
229 |
get { return name_; } |
230 |
} |
231 |
|
232 |
/// <summary> |
233 |
/// The applicable exception. |
234 |
/// </summary> |
235 |
public Exception Exception |
236 |
{ |
237 |
get { return exception_; } |
238 |
} |
239 |
|
240 |
/// <summary> |
241 |
/// Get / set a value indicating wether scanning should continue. |
242 |
/// </summary> |
243 |
public bool ContinueRunning { get; set; } |
244 |
|
245 |
#region Instance Fields |
246 |
|
247 |
private readonly Exception exception_; |
248 |
private readonly string name_; |
249 |
|
250 |
#endregion |
251 |
} |
252 |
|
253 |
/// <summary> |
254 |
/// Delegate invoked before starting to process a directory. |
255 |
/// </summary> |
256 |
public delegate void ProcessDirectoryHandler(object sender, DirectoryEventArgs e); |
257 |
|
258 |
/// <summary> |
259 |
/// Delegate invoked before starting to process a file. |
260 |
/// </summary> |
261 |
/// <param name="sender">The source of the event</param> |
262 |
/// <param name="e">The event arguments.</param> |
263 |
public delegate void ProcessFileHandler(object sender, ScanEventArgs e); |
264 |
|
265 |
/// <summary> |
266 |
/// Delegate invoked during processing of a file or directory |
267 |
/// </summary> |
268 |
/// <param name="sender">The source of the event</param> |
269 |
/// <param name="e">The event arguments.</param> |
270 |
public delegate void ProgressHandler(object sender, ProgressEventArgs e); |
271 |
|
272 |
/// <summary> |
273 |
/// Delegate invoked when a file has been completely processed. |
274 |
/// </summary> |
275 |
/// <param name="sender">The source of the event</param> |
276 |
/// <param name="e">The event arguments.</param> |
277 |
public delegate void CompletedFileHandler(object sender, ScanEventArgs e); |
278 |
|
279 |
/// <summary> |
280 |
/// Delegate invoked when a directory failure is detected. |
281 |
/// </summary> |
282 |
/// <param name="sender">The source of the event</param> |
283 |
/// <param name="e">The event arguments.</param> |
284 |
public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e); |
285 |
|
286 |
/// <summary> |
287 |
/// Delegate invoked when a file failure is detected. |
288 |
/// </summary> |
289 |
/// <param name="sender">The source of the event</param> |
290 |
/// <param name="e">The event arguments.</param> |
291 |
public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e); |
292 |
|
293 |
/// <summary> |
294 |
/// FileSystemScanner provides facilities scanning of files and directories. |
295 |
/// </summary> |
296 |
public class FileSystemScanner |
297 |
{ |
298 |
#region Constructors |
299 |
|
300 |
/// <summary> |
301 |
/// Initialise a new instance of <see cref="FileSystemScanner"></see> |
302 |
/// </summary> |
303 |
/// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param> |
304 |
public FileSystemScanner(string filter) |
305 |
{ |
306 |
fileFilter_ = new PathFilter(filter); |
307 |
} |
308 |
|
309 |
/// <summary> |
310 |
/// Initialise a new instance of <see cref="FileSystemScanner"></see> |
311 |
/// </summary> |
312 |
/// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param> |
313 |
/// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param> |
314 |
public FileSystemScanner(string fileFilter, string directoryFilter) |
315 |
{ |
316 |
fileFilter_ = new PathFilter(fileFilter); |
317 |
directoryFilter_ = new PathFilter(directoryFilter); |
318 |
} |
319 |
|
320 |
/// <summary> |
321 |
/// Initialise a new instance of <see cref="FileSystemScanner"></see> |
322 |
/// </summary> |
323 |
/// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param> |
324 |
public FileSystemScanner(IScanFilter fileFilter) |
325 |
{ |
326 |
fileFilter_ = fileFilter; |
327 |
} |
328 |
|
329 |
/// <summary> |
330 |
/// Initialise a new instance of <see cref="FileSystemScanner"></see> |
331 |
/// </summary> |
332 |
/// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param> |
333 |
/// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see> to apply.</param> |
334 |
public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter) |
335 |
{ |
336 |
fileFilter_ = fileFilter; |
337 |
directoryFilter_ = directoryFilter; |
338 |
} |
339 |
|
340 |
#endregion |
341 |
|
342 |
/// <summary> |
343 |
/// Delegate to invoke when processing for a file has finished. |
344 |
/// </summary> |
345 |
public CompletedFileHandler CompletedFile; |
346 |
|
347 |
/// <summary> |
348 |
/// Delegate to invoke when a directory failure is detected. |
349 |
/// </summary> |
350 |
public DirectoryFailureHandler DirectoryFailure; |
351 |
|
352 |
/// <summary> |
353 |
/// Delegate to invoke when a file failure is detected. |
354 |
/// </summary> |
355 |
public FileFailureHandler FileFailure; |
356 |
|
357 |
/// <summary> |
358 |
/// Delegate to invoke when a directory is processed. |
359 |
/// </summary> |
360 |
public ProcessDirectoryHandler ProcessDirectory; |
361 |
|
362 |
/// <summary> |
363 |
/// Delegate to invoke when a file is processed. |
364 |
/// </summary> |
365 |
public ProcessFileHandler ProcessFile; |
366 |
|
367 |
/// <summary> |
368 |
/// Raise the DirectoryFailure event. |
369 |
/// </summary> |
370 |
/// <param name="directory">The directory name.</param> |
371 |
/// <param name="e">The exception detected.</param> |
372 |
private void OnDirectoryFailure(string directory, Exception e) |
373 |
{ |
374 |
if (DirectoryFailure == null) |
375 |
{ |
376 |
alive_ = false; |
377 |
} |
378 |
else |
379 |
{ |
380 |
var args = new ScanFailureEventArgs(directory, e); |
381 |
DirectoryFailure(this, args); |
382 |
alive_ = args.ContinueRunning; |
383 |
} |
384 |
} |
385 |
|
386 |
/// <summary> |
387 |
/// Raise the FileFailure event. |
388 |
/// </summary> |
389 |
/// <param name="file">The file name.</param> |
390 |
/// <param name="e">The exception detected.</param> |
391 |
private void OnFileFailure(string file, Exception e) |
392 |
{ |
393 |
if (FileFailure == null) |
394 |
{ |
395 |
alive_ = false; |
396 |
} |
397 |
else |
398 |
{ |
399 |
var args = new ScanFailureEventArgs(file, e); |
400 |
FileFailure(this, args); |
401 |
alive_ = args.ContinueRunning; |
402 |
} |
403 |
} |
404 |
|
405 |
/// <summary> |
406 |
/// Raise the ProcessFile event. |
407 |
/// </summary> |
408 |
/// <param name="file">The file name.</param> |
409 |
private void OnProcessFile(string file) |
410 |
{ |
411 |
if (ProcessFile != null) |
412 |
{ |
413 |
var args = new ScanEventArgs(file); |
414 |
ProcessFile(this, args); |
415 |
alive_ = args.ContinueRunning; |
416 |
} |
417 |
} |
418 |
|
419 |
/// <summary> |
420 |
/// Raise the complete file event |
421 |
/// </summary> |
422 |
/// <param name="file">The file name</param> |
423 |
private void OnCompleteFile(string file) |
424 |
{ |
425 |
if (CompletedFile == null) |
426 |
{ |
427 |
return; |
428 |
} |
429 |
var args = new ScanEventArgs(file); |
430 |
CompletedFile(this, args); |
431 |
alive_ = args.ContinueRunning; |
432 |
} |
433 |
|
434 |
/// <summary> |
435 |
/// Raise the ProcessDirectory event. |
436 |
/// </summary> |
437 |
/// <param name="directory">The directory name.</param> |
438 |
/// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param> |
439 |
private void OnProcessDirectory(string directory, bool hasMatchingFiles) |
440 |
{ |
441 |
if (ProcessDirectory != null) |
442 |
{ |
443 |
var args = new DirectoryEventArgs(directory, hasMatchingFiles); |
444 |
ProcessDirectory(this, args); |
445 |
alive_ = args.ContinueRunning; |
446 |
} |
447 |
} |
448 |
|
449 |
/// <summary> |
450 |
/// Scan a directory. |
451 |
/// </summary> |
452 |
/// <param name="directory">The base directory to scan.</param> |
453 |
/// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param> |
454 |
public void Scan(string directory, bool recurse) |
455 |
{ |
456 |
alive_ = true; |
457 |
ScanDir(directory, recurse); |
458 |
} |
459 |
|
460 |
private void ScanDir(string directory, bool recurse) |
461 |
{ |
462 |
try |
463 |
{ |
464 |
#if !SL4 |
465 |
var names = Directory.GetFiles(directory); |
466 |
#else |
467 |
var names = Directory.EnumerateFiles(directory).ToArray(); |
468 |
#endif |
469 |
var hasMatch = false; |
470 |
for (var fileIndex = 0; fileIndex < names.Length; ++fileIndex) |
471 |
{ |
472 |
if (!fileFilter_.IsMatch(names[fileIndex])) |
473 |
{ |
474 |
names[fileIndex] = null; |
475 |
} |
476 |
else |
477 |
{ |
478 |
hasMatch = true; |
479 |
} |
480 |
} |
481 |
|
482 |
OnProcessDirectory(directory, hasMatch); |
483 |
|
484 |
if (alive_ && hasMatch) |
485 |
{ |
486 |
foreach (var fileName in names) |
487 |
{ |
488 |
try |
489 |
{ |
490 |
if (fileName != null) |
491 |
{ |
492 |
OnProcessFile(fileName); |
493 |
if (!alive_) |
494 |
{ |
495 |
break; |
496 |
} |
497 |
} |
498 |
} |
499 |
catch (Exception e) |
500 |
{ |
501 |
OnFileFailure(fileName, e); |
502 |
} |
503 |
} |
504 |
} |
505 |
} |
506 |
catch (Exception e) |
507 |
{ |
508 |
OnDirectoryFailure(directory, e); |
509 |
} |
510 |
|
511 |
if (alive_ && recurse) |
512 |
{ |
513 |
try |
514 |
{ |
515 |
#if !SL4 |
516 |
var names = Directory.GetDirectories(directory); |
517 |
#else |
518 |
var names = System.IO.Directory.EnumerateDirectories(directory); |
519 |
#endif |
520 |
foreach (var fulldir in names) |
521 |
{ |
522 |
if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) |
523 |
{ |
524 |
ScanDir(fulldir, true); |
525 |
if (!alive_) |
526 |
{ |
527 |
break; |
528 |
} |
529 |
} |
530 |
} |
531 |
} |
532 |
catch (Exception e) |
533 |
{ |
534 |
OnDirectoryFailure(directory, e); |
535 |
} |
536 |
} |
537 |
} |
538 |
|
539 |
#region Instance Fields |
540 |
|
541 |
/// <summary> |
542 |
/// The directory filter currently in use. |
543 |
/// </summary> |
544 |
private readonly IScanFilter directoryFilter_; |
545 |
|
546 |
/// <summary> |
547 |
/// The file filter currently in use. |
548 |
/// </summary> |
549 |
private readonly IScanFilter fileFilter_; |
550 |
|
551 |
/// <summary> |
552 |
/// Flag indicating if scanning should continue running. |
553 |
/// </summary> |
554 |
private bool alive_; |
555 |
|
556 |
#endregion |
557 |
} |
558 |
} |