Queue through all files in a directory (and subdirectories).
-
Here is an easy way to queue all files in a folder (and subfolders). You only need to initialize it with
_folders.Enqueue(SomeRootDirectoryInfo);
before using it...private Queue _folders = new Queue();
private Queue _files = new Queue();public FileInfo NextFile
{
get
{
lock (_files)
{
if (_files.Count != 0)
return _files.Dequeue();
else
{
lock (_folders)
{
while (_folders.Count != 0)
{
DirectoryInfo dir = _folders.Dequeue();
foreach (DirectoryInfo d in dir.GetDirectories())
_folders.Enqueue(d);
foreach (FileInfo f in dir.GetFiles())
_files.Enqueue(f);
if (_files.Count != 0) return _files.Dequeue();
}
}
}
}
return null; //Default
}
}I quite like this. The tradeoff you pay for not loading everything into memory and enumerating the whole tree up front is that there is no indicator of how far through you are. It would be even cleverer if it implemented IEnumerable<FileInfo> so you can foreach over it:
class LazyFolderTree : IEnumerable<FileInfo> {
private Queue<DirectoryInfo> _folders = new Queue<DirectoryInfo>();
private Queue<FileInfo> _files = new Queue<FileInfo>();public LazyFolderTree(DirectoryInfo root) { _folders.Enqueue(root); }
public FileInfo NextFile {
get
{
lock (_files)
{
if (_files.Count != 0)
return _files.Dequeue();
else
{
lock (_folders)
{
while (_folders.Count != 0)
{
DirectoryInfo dir = _folders.Dequeue();
foreach (DirectoryInfo d in dir.GetDirectories())
_folders.Enqueue(d);
foreach (FileInfo f in dir.GetFiles())
_files.Enqueue(f);
if (_files.Count != 0) return _files.Dequeue();
}
}
}
}
return null; //Default
}
}public IEnumerator<FileInfo> GetEnumerator() { return new Enumerator(this); }
// I think you need to implement this too?
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }private class Enumerator : IEnumerator<FileInfo> {
LazyFolderTree host;
FileInfo current = null;Enumerator(LazyFolderTree host) { this.host = host; }
public bool MoveNext(){ return null != current = host.NextFile; }
public FileInfo Current { get { return current; } }
object System.Collections.IEnumerable.Current { get { return current; } }
public void Reset() { throw new NotSupportedException("Can't reset this enumerator."); }
}
} -
I quite like this. The tradeoff you pay for not loading everything into memory and enumerating the whole tree up front is that there is no indicator of how far through you are. It would be even cleverer if it implemented IEnumerable<FileInfo> so you can foreach over it:
class LazyFolderTree : IEnumerable<FileInfo> {
private Queue<DirectoryInfo> _folders = new Queue<DirectoryInfo>();
private Queue<FileInfo> _files = new Queue<FileInfo>();public LazyFolderTree(DirectoryInfo root) { _folders.Enqueue(root); }
public FileInfo NextFile {
get
{
lock (_files)
{
if (_files.Count != 0)
return _files.Dequeue();
else
{
lock (_folders)
{
while (_folders.Count != 0)
{
DirectoryInfo dir = _folders.Dequeue();
foreach (DirectoryInfo d in dir.GetDirectories())
_folders.Enqueue(d);
foreach (FileInfo f in dir.GetFiles())
_files.Enqueue(f);
if (_files.Count != 0) return _files.Dequeue();
}
}
}
}
return null; //Default
}
}public IEnumerator<FileInfo> GetEnumerator() { return new Enumerator(this); }
// I think you need to implement this too?
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }private class Enumerator : IEnumerator<FileInfo> {
LazyFolderTree host;
FileInfo current = null;Enumerator(LazyFolderTree host) { this.host = host; }
public bool MoveNext(){ return null != current = host.NextFile; }
public FileInfo Current { get { return current; } }
object System.Collections.IEnumerable.Current { get { return current; } }
public void Reset() { throw new NotSupportedException("Can't reset this enumerator."); }
}
}> The tradeoff you pay for not loading everything into memory and enumerating the whole tree up front is that there is no indicator of how far through you are. Isn't there a smart thing to do using 'yield return'? Maybe some C# wizard could answer that...
'As programmers go, I'm fairly social. Which still means I'm a borderline sociopath by normal standards.' Jeff Atwood
-
Hi Timothy, I think there is something missing. Where does the NextFile method come into it?
"You get that on the big jobs."
NextFile is a property, not a method. It could be used simply as:
FileInfo myFile = NextFile;
while (myFile != null)
{
//Do stuff!myFile = NextFile;
}
etc...
-
NextFile is a property, not a method. It could be used simply as:
FileInfo myFile = NextFile;
while (myFile != null)
{
//Do stuff!myFile = NextFile;
}
etc...
Ok so you have a property that behaves like a method. I'm guessing the FileInfo class is in a different namespace to system.IO which will cause issues with aliasing. And then what happens when two files in different folders have the same name? I'm sure it is smart code, I just don't get it from the snippet provided. Maybe a more complete example is required?
"You get that on the big jobs."
-
Ok so you have a property that behaves like a method. I'm guessing the FileInfo class is in a different namespace to system.IO which will cause issues with aliasing. And then what happens when two files in different folders have the same name? I'm sure it is smart code, I just don't get it from the snippet provided. Maybe a more complete example is required?
"You get that on the big jobs."
RobCroll wrote:
I'm guessing the FileInfo class is in a different namespace to system.IO
What would make you think that? FileInfo is part of the System.IO namespace.
RobCroll wrote:
And then what happens when two files in different folders have the same name?
Why would that be a problem? The FileInfo class holds the full path to the specific file, no matter what the "short" name is. Yes, you could remove the "get" accessor and turn this property into a parameterless method, also.
-
> The tradeoff you pay for not loading everything into memory and enumerating the whole tree up front is that there is no indicator of how far through you are. Isn't there a smart thing to do using 'yield return'? Maybe some C# wizard could answer that...
'As programmers go, I'm fairly social. Which still means I'm a borderline sociopath by normal standards.' Jeff Atwood
-
Yes probably (I think yield return is essentially a way of building an IEnumerable like this but without having to type stuff). I haven't ever used it or really got familiar with it though.
BobJanova wrote:
Yes probably (I think yield return is essentially a way of building an IEnumerable like this but without having to type stuff). I haven't ever used it or really got familiar with it though.
It's actually pretty simple... It would go something like this:
public IEnumerable<FileInfo> EnumerateFiles(DirectoryInfo rootDirectory)
{
Queue<DirectoryInfo> dirs = new Queue<DirectoryInfo();
dirs.Enqueue(rootDirectory);while (dirs.Count != 0)
{
DirectoryInfo dir = dirs.Dequeue();
foreach (DirectoryInfo d in dir.GetDirectories())
dirs.Enqueue(d);
foreach (FileInfo f in dir.GetFiles())
yield return f;
}
}(Just typed here, so not tested or debugged)
Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels) -
BobJanova wrote:
Yes probably (I think yield return is essentially a way of building an IEnumerable like this but without having to type stuff). I haven't ever used it or really got familiar with it though.
It's actually pretty simple... It would go something like this:
public IEnumerable<FileInfo> EnumerateFiles(DirectoryInfo rootDirectory)
{
Queue<DirectoryInfo> dirs = new Queue<DirectoryInfo();
dirs.Enqueue(rootDirectory);while (dirs.Count != 0)
{
DirectoryInfo dir = dirs.Dequeue();
foreach (DirectoryInfo d in dir.GetDirectories())
dirs.Enqueue(d);
foreach (FileInfo f in dir.GetFiles())
yield return f;
}
}(Just typed here, so not tested or debugged)
Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels)Why queue the directories? GetDirectories() returns an array, so putting them in a collection seems redundant. Some error handling wouldn't hurt either. If an exception is thrown, the entire operation fails.
-
Why queue the directories? GetDirectories() returns an array, so putting them in a collection seems redundant. Some error handling wouldn't hurt either. If an exception is thrown, the entire operation fails.
Wasn't meant to be perfect... Just a demonstration on how to use yields.
Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels) -
Wasn't meant to be perfect... Just a demonstration on how to use yields.
Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels)No biggie. Recursion would be ideal for this scenario. ;)