(8/8/05: I fixed the source code)
Just like String::Split, I dislike those GetFiles methods that put more load on the managed heap when all I need is just one piece of information among the several it gives me (130,000 filenames in my project!).
So I wrote the following to wrap the FindFirstFile/FindNextFile/FindClose and it allows me to do the following:
foreach( FoundFileData ffd in new FilesFinder( @"C:\Windows\*.DLL" ) )
Console.WriteLine( "\"{0}\" {1} {2} {3}", ffd.FileName, ffd.Size, ffd.CreationTime, ffd.Attributes ) ;
I'm sure this can be improved so don't hesitate to comment.and let's make it better together! I compiled it with VC++ 2005 July CTP.
// FilesFinder.h
#pragma once
#include <Windows.h>
#include <vcclr.h>
#include <new>
using namespace System;
using namespace System::Collections::Generic ;
using namespace System::IO ;
using namespace System::Diagnostics ;
namespace Microsoft { namespace Services { namespace Partners { namespace ISV
{
public ref class FoundFileData
internal:
FoundFileData( const WIN32_FIND_DATA % win32FindData )
:Attributes( (FileAttributes) win32FindData.dwFileAttributes ),
CreationTime( DateTime::FromFileTime( ((UInt64) win32FindData.ftCreationTime.dwHighDateTime << 32) + win32FindData.ftCreationTime.dwLowDateTime) ),
LastAccessTime( DateTime::FromFileTime(((UInt64) win32FindData.ftLastAccessTime.dwHighDateTime << 32) + win32FindData.ftLastAccessTime.dwLowDateTime) ),
LastWriteTime( DateTime::FromFileTime(((UInt64) win32FindData.ftLastWriteTime.dwHighDateTime << 32) + win32FindData.ftLastWriteTime.dwLowDateTime) ),
Size( ((UInt64) win32FindData.nFileSizeHigh << 32) + win32FindData.nFileSizeLow ),
FileName( gcnew String(win32FindData.cFileName) ),
AlternateFileName( gcnew String(win32FindData.cAlternateFileName) )
}
public:
initonly FileAttributes Attributes ;
initonly DateTime CreationTime;
initonly DateTime LastAccessTime;
initonly DateTime LastWriteTime;
initonly UInt64 Size ;
initonly String ^ FileName;
initonly String ^ AlternateFileName ;
} ;
public ref class FilesEnumerator : IEnumerator<FoundFileData ^>
initonly String ^ _fileName ;
WIN32_FIND_DATA * _win32FindData ;
HANDLE _findHandle ;
FilesEnumerator( String ^ fileName )
_fileName = fileName ;
_findHandle = INVALID_HANDLE_VALUE ;
try
_win32FindData = new WIN32_FIND_DATA() ;
catch( const std::bad_alloc & e )
throw gcnew OutOfMemoryException( gcnew String( e.what() ) ) ;
FilesEnumerator( FilesEnumerator % filesEnumerator )
System::Diagnostics::Debug::Assert( false, "TODO" ) ;
~FilesEnumerator()
FilesEnumerator::!FilesEnumerator() ; // 8/8/05: added (Thanks Andy Rich). See http://blogs.msdn.com/arich/archive/2005/06/09/427389.aspx
!FilesEnumerator()
if ( _findHandle != INVALID_HANDLE_VALUE )
FindClose(_findHandle);
if ( _win32FindData != NULL )
delete _win32FindData ;
_win32FindData = NULL ;
virtual property Object ^ CurrentObject // 8/8/05: name change
Object ^ get () = System::Collections::IEnumerator::Current::get
return Current::get() ;
virtual property FoundFileData ^ Current
FoundFileData ^ get ()
if ( _findHandle == INVALID_HANDLE_VALUE )
throw gcnew InvalidOperationException( "MoveNext() must be called first" ) ;
return gcnew FoundFileData(*_win32FindData) ;
virtual bool MoveNext()
if (_findHandle == INVALID_HANDLE_VALUE)
pin_ptr<const wchar_t> nativefileName = PtrToStringChars(_fileName) ;
_findHandle = FindFirstFile( nativefileName, _win32FindData);
DWORD lastError = GetLastError() ;
if ( lastError == ERROR_FILE_NOT_FOUND )
return false ;
throw gcnew System::ComponentModel::Win32Exception( lastError ) ;
else
if ( ! FindNextFile( _findHandle, _win32FindData ) )
if ( lastError == ERROR_NO_MORE_FILES )
return true ;
virtual void Reset()
public ref class FilesFinder : public IEnumerable<FoundFileData ^>
String ^ _fileName ;
FilesFinder( String ^ fileName ) : _fileName(fileName)
// 8/8/05: name change
virtual System::Collections::IEnumerator ^ GetObjectEnumerator() = System::Collections::IEnumerable::GetEnumerator
return GetEnumerator() ;
virtual IEnumerator<FoundFileData ^> ^ GetEnumerator()
return gcnew FilesEnumerator(_fileName) ;
};
}}}}