Reputation: 6469
I'm populating a "file explorer" solution by using c#. Here's my code:
namespace NIXplorer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
TreeNode root = new TreeNode("Desktop");
TreeNode doc = new TreeNode("My Documents");
TreeNode comp = new TreeNode("My Computer ");
TreeNode drivenode;
TreeNode filenode;
DirectoryInfo dir;
string path = "";
private void Form1_Load(object sender, EventArgs e)
{
listView1.LabelEdit = true;
listView1.FullRowSelect = true;
listView1.Sorting = SortOrder.Ascending;
treeView1.Nodes.Add(root);
root.ImageIndex = 0;
doc.ImageIndex = 1;
comp.ImageIndex = 2;
treeView1.Nodes.Add(doc);
treeView1.Nodes.Add(comp);
GetDrives();
}
private void GetDrives()
{
DriveInfo[] drive = DriveInfo.GetDrives();
foreach (DriveInfo d in drive)
{
drivenode = new TreeNode(d.Name);
dir = d.RootDirectory;
comp.Nodes.Add(drivenode);
//drivenode.ImageIndex = 3;
switch (d.DriveType)
{
case DriveType.CDRom:
drivenode.ImageIndex = 5;
break;
//case DriveType.Fixed:
// drivenode.ImageIndex = 1;
// break;
case DriveType.Removable:
drivenode.ImageIndex = 8;
break;
//case DriveType.NoRootDirectory:
// drivenode.ImageIndex = 5;
// break;
case DriveType.Network:
drivenode.ImageIndex = 6;
break;
default:
drivenode.ImageIndex = 7;
break;
}
getFilesAndDir(drivenode, dir);
}
}
private void getFilesAndDir(TreeNode node, DirectoryInfo dirname)
{
try
{
foreach (FileInfo fi in dirname.GetFiles())
{
filenode = new TreeNode(fi.Name);
filenode.Name = fi.FullName;
//filenode.ImageIndex = 5;
getFileExtension(filenode.Name);
node.Nodes.Add(filenode);
}
try
{
foreach (DirectoryInfo di in dirname.GetDirectories())
{
TreeNode dirnode = new TreeNode(di.Name);
dirnode.ImageIndex = 4;
dirnode.Name = di.FullName;
node.Nodes.Add(dirnode);
getFilesAndDir(dirnode, di); //Recursive Functioning
}
}
catch (Exception e1)
{
}
}
catch (Exception e1)
{
}
}
private void getFileExtension(string filename)
{
switch (Path.GetExtension(filename))
{
case ".txt":
filenode.ImageIndex = 17;
break;
case ".rtf":
filenode.ImageIndex = 16;
break;
case ".doc":
case ".docx":
filenode.ImageIndex = 9;
break;
case ".html":
case ".htm":
filenode.ImageIndex = 13;
break;
case ".rar":
case ".zip":
filenode.ImageIndex = 10;
break;
case ".exe":
filenode.ImageIndex = 12;
break;
case ".mp3":
case ".wma":
case ".flac":
case ".m4a":
filenode.ImageIndex = 11;
break;
case ".mp4":
case ".flv":
case ".mkv":
case ".webm":
filenode.ImageIndex = 18;
break;
case ".ico":
case ".png":
case ".jpg":
case ".jpeg":
case ".psd":
filenode.ImageIndex = 14;
break;
default:
filenode.ImageIndex = 15;
break;
}
}
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
try
{
listView1.Items.Clear();
TreeNode selectednode = e.Node;
treeView1.SelectedNode.ImageIndex = e.Node.ImageIndex;
selectednode.Expand();
comboBox1.Text = selectednode.FullPath;
if (selectednode.Nodes.Count > 0)
{
foreach (TreeNode n in selectednode.Nodes)
{
ListViewItem lst = new ListViewItem(n.Text, n.ImageIndex);
lst.Name = n.FullPath.Substring(13);
//MessageBox.Show("List Node : " + lst.Name);
listView1.Items.Add(lst);
}
}
else
{
listView1.Items.Add(selectednode.FullPath, selectednode.Text, selectednode.ImageIndex);
}
}
catch (Exception e1)
{
}
}
}
}
I build this solution in VS2012 and this algorithm seems not the best choice 'cause everytime i debug this solution, it takes like more than 1 or 2 minutes to start ... this really bad... Hope you guys can help with a better solution or algorithm ? That'd be great. Thanks in advance !
Upvotes: 1
Views: 734
Reputation: 73462
Loading all the directories and files are expensive IO operations. don't load everything when there is no need. user is not going to view everything all the time.
I'll suggest you to populate on demand. Something like this.
class FileSystemObject
{
public FileSystemInfo FileSystemInfo;
public FileSystemObjectType ObjectType;
public bool SubNodesLoaded;
}
enum FileSystemObjectType
{
File = 1,
Directory = 2
}
private void GetDrives()
{
DriveInfo[] drive = DriveInfo.GetDrives();
foreach (DriveInfo d in drive)
{
drivenode = new TreeNode(d.Name);
dir = d.RootDirectory;
drivenode.Tag = new FileSystemObject { FileSystemInfo = dir, ObjectType = FileSystemObjectType.Directory };
comp.Nodes.Add(drivenode);
//drivenode.ImageIndex = 3;
switch (d.DriveType)
{
case DriveType.CDRom:
drivenode.ImageIndex = 5;
break;
//case DriveType.Fixed:
// drivenode.ImageIndex = 1;
// break;
case DriveType.Removable:
drivenode.ImageIndex = 8;
break;
//case DriveType.NoRootDirectory:
// drivenode.ImageIndex = 5;
// break;
case DriveType.Network:
drivenode.ImageIndex = 6;
break;
default:
drivenode.ImageIndex = 7;
break;
}
EnsureChildsLoaded(drivenode);
}
}
private void EnsureChildsLoaded(TreeNode node)
{
try
{
FileSystemObject info = (FileSystemObject)node.Tag;
if (info == null || info.ObjectType == FileSystemObjectType.File || info.SubNodesLoaded)
{
return;
}
DirectoryInfo dirInfo = (DirectoryInfo)info.FileSystemInfo;
// while (!new DriveInfo(dirInfo.Root.FullName).IsReady)
{
dirInfo.Refresh();
}
foreach (FileInfo fi in dirInfo.GetFiles())
{
filenode = new TreeNode(fi.Name);
filenode.Name = fi.FullName;
//filenode.ImageIndex = 5;
getFileExtension(filenode.Name);
filenode.Tag = new FileSystemObject { FileSystemInfo = fi, ObjectType = FileSystemObjectType.File };
node.Nodes.Add(filenode);
}
foreach (DirectoryInfo di in dirInfo.GetDirectories())
{
TreeNode dirnode = new TreeNode(di.Name);
dirnode.ImageIndex = 4;
dirnode.Name = di.FullName;
dirnode.Tag = new FileSystemObject { FileSystemInfo = di, ObjectType = FileSystemObjectType.Directory };
node.Nodes.Add(dirnode);
}
info.SubNodesLoaded = true;
}
catch (Exception ex){//log it }
}
private void treeView1_AfterExpand(object sender, TreeViewEventArgs e)
{
//Load two level of nodes on demand
FileSystemObject info = (FileSystemObject)e.Node.Tag;
EnsureChildsLoaded(e.Node);
foreach (TreeNode node in e.Node.Nodes)
{
EnsureChildsLoaded(node);
}
}
Your getFilesAndDir
method not required. rest all same. Feel free to ask any clarification.
Hope this helps.
Upvotes: 1
Reputation: 6039
GetFiles
is inherently slow because you have to wait for the whole array of names to be returned before you can interact with it.
If you use Directory.EnumerateFiles
instead, you can start enumerating through the collection (and filling your tree) before it is all returned.
http://msdn.microsoft.com/en-us/library/dd383458.aspx
Upvotes: 0