You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
161
mcs/class/referencesource/System.Web/Util/FileEnumerator.cs
Normal file
161
mcs/class/referencesource/System.Web/Util/FileEnumerator.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="FileEnumerator.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* FileEnumerator class
|
||||
*
|
||||
* Copyright (c) 2003 Microsoft Corporation
|
||||
*
|
||||
* Class to efficiently enumerate the files in a directory. The only thing the framework provides
|
||||
* to do this is Directory.GetFiles(), which is unusable on large directories because it returns an
|
||||
* array containing all the file names at once (huge memory allocation).
|
||||
*
|
||||
* An efficient alternative is to use FindFirstFile/FindNextFile, which works but requires a lot
|
||||
* more code. Also, it makes our code base harder to port to non-windows platforms.
|
||||
*
|
||||
* This FileEnumerator class solves both problem, by providing a simple and efficient wrapper.
|
||||
* By working with a single object, it is almost as efficient as calling FindFirstFile/FindNextFile,
|
||||
* but is much easier to use. e.g. instead of:
|
||||
*
|
||||
* UnsafeNativeMethods.WIN32_FIND_DATA wfd;
|
||||
* IntPtr hFindFile = UnsafeNativeMethods.FindFirstFile(physicalDir + @"\*.*", out wfd);
|
||||
*
|
||||
* if (hFindFile == INVALID_HANDLE_VALUE)
|
||||
* return;
|
||||
*
|
||||
* try {
|
||||
* for (bool more=true; more; more=UnsafeNativeMethods.FindNextFile(hFindFile, out wfd)) {
|
||||
*
|
||||
* // Skip false directories
|
||||
* if (wfd.cFileName == "." || wfd.cFileName == "..")
|
||||
* continue;
|
||||
*
|
||||
* string fullPath = Path.Combine(physicalDir, wfd.cFileName);
|
||||
*
|
||||
* ProcessFile(fullPath);
|
||||
* }
|
||||
* }
|
||||
* finally {
|
||||
* UnsafeNativeMethods.FindClose(hFindFile);
|
||||
* }
|
||||
*
|
||||
* we can simply write
|
||||
*
|
||||
* foreach (FileData fileData in FileEnumerator.Create(physicalDir)) {
|
||||
* ProcessFile(fileData.FullName);
|
||||
* }
|
||||
*/
|
||||
|
||||
|
||||
namespace System.Web.Util {
|
||||
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
|
||||
/*
|
||||
* This is a somewhat artificial base class for FileEnumerator. The main reason
|
||||
* for it is to allow user code to be more readable, by looking like:
|
||||
* foreach (FileData fileData in FileEnumerator.Create(path)) { ... }
|
||||
* instead of
|
||||
* foreach (FileEnumerator fileData in FileEnumerator.Create(path)) { ... }
|
||||
*/
|
||||
internal abstract class FileData {
|
||||
|
||||
protected string _path;
|
||||
protected UnsafeNativeMethods.WIN32_FIND_DATA _wfd;
|
||||
|
||||
internal string Name {
|
||||
get { return _wfd.cFileName; }
|
||||
}
|
||||
|
||||
internal string FullName {
|
||||
get { return _path + @"\" + _wfd.cFileName; }
|
||||
}
|
||||
|
||||
internal bool IsDirectory {
|
||||
get { return (_wfd.dwFileAttributes & UnsafeNativeMethods.FILE_ATTRIBUTE_DIRECTORY) != 0; }
|
||||
}
|
||||
|
||||
internal bool IsHidden {
|
||||
get { return (_wfd.dwFileAttributes & UnsafeNativeMethods.FILE_ATTRIBUTE_HIDDEN) != 0; }
|
||||
}
|
||||
|
||||
internal FindFileData GetFindFileData() {
|
||||
return new FindFileData(ref _wfd);
|
||||
}
|
||||
}
|
||||
|
||||
internal class FileEnumerator: FileData, IEnumerable, IEnumerator, IDisposable {
|
||||
private IntPtr _hFindFile = UnsafeNativeMethods.INVALID_HANDLE_VALUE;
|
||||
|
||||
internal static FileEnumerator Create(string path) {
|
||||
return new FileEnumerator(path);
|
||||
}
|
||||
|
||||
private FileEnumerator(string path) {
|
||||
_path = Path.GetFullPath(path);
|
||||
}
|
||||
|
||||
~FileEnumerator() {
|
||||
((IDisposable)this).Dispose();
|
||||
}
|
||||
|
||||
// Should the current file be excluded from the enumeration
|
||||
private bool SkipCurrent() {
|
||||
|
||||
// Skip false directories
|
||||
if (_wfd.cFileName == "." || _wfd.cFileName == "..")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We just return ourselves for the enumerator, to avoid creating a new object
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
bool IEnumerator.MoveNext() {
|
||||
|
||||
for (;;) {
|
||||
if (_hFindFile == UnsafeNativeMethods.INVALID_HANDLE_VALUE) {
|
||||
_hFindFile = UnsafeNativeMethods.FindFirstFile(_path + @"\*.*", out _wfd);
|
||||
|
||||
// Empty enumeration case
|
||||
if (_hFindFile == UnsafeNativeMethods.INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
bool hasMoreFiles = UnsafeNativeMethods.FindNextFile(_hFindFile, out _wfd);
|
||||
if (!hasMoreFiles)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SkipCurrent())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// The current object of the enumeration is always ourselves. No new object created.
|
||||
object IEnumerator.Current {
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
void IEnumerator.Reset() {
|
||||
// We don't support reset, though it would be easy to add if needed
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
if (_hFindFile != UnsafeNativeMethods.INVALID_HANDLE_VALUE) {
|
||||
UnsafeNativeMethods.FindClose(_hFindFile);
|
||||
_hFindFile = UnsafeNativeMethods.INVALID_HANDLE_VALUE;
|
||||
}
|
||||
System.GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user