I'm trying to pull together a treeview with folders of mixed classes. The root folders are one class and subfolders are another, like this:
Root Folder #1 <-- DirectoryItem class
--Sub Folder <-- SubDirectoryItem class
----file <-- FileItem class
Root Folder #2 <-- DirectoryItem class
--Sub Folder <-- SubDirectoryItem class
----file <-- FileItem class
I've been attempting to combine two different recursive methods so the subfolders are retrieved as "SubDirectoryItems" instead of "DirectoryItem" I'll spare that code attempt due to lack of clarify, but I'm wondering if there's a better approach?
class ItemProvider
{
public List<Item> GetItems(string path, SearchOption searchOption)
{
var items = new List<Item>();
var dirInfo = new DirectoryInfo(path);
foreach (var directory in dirInfo.GetDirectories("*.*", SearchOption.TopDirectoryOnly))
{
var item = new DirectoryItem
{
Name = directory.Name,
Path = directory.FullName,
Items = GetItems(directory.FullName, SearchOption.AllDirectories)
};
items.Add(item);
}
foreach (var subdirectory in dirInfo.GetDirectories("*.*", SearchOption.TopDirectoryOnly))
{
var item = new SubDirectoryItem()
{
Name = subdirectory.Name,
Path = subdirectory.FullName,
Items = GetItems(subdirectory.FullName, SearchOption.AllDirectories)
};
items.Add(item);
}
foreach (var file in dirInfo.GetFiles())
{
var item = new FileItem
{
Name = file.Name,
Path = file.FullName
};
items.Add(item);
}
return items;
}
}
}
I was able to figure it out. I made the first list TopDirectoryOnly then pulled in the rest of the items via a 2nd list for AllDirectories. Here's the code in case it helps any other beginners (like me):
class ItemProvider
{
public List<Item> GetItems(string path, SearchOption searchOption)
{
var items = new List<Item>();
var dirInfo = new DirectoryInfo(path);
foreach (var directory in dirInfo.GetDirectories("*.*", SearchOption.TopDirectoryOnly))
{
var item = new DirectoryItem
{
Name = directory.Name,
Path = directory.FullName,
Items = GetSubItems(directory.FullName, SearchOption.AllDirectories)
};
items.Add(item);
}
return items;
}
public List<Item> GetSubItems(string path, SearchOption searchOption)
{
var items = new List<Item>();
var dirInfo = new DirectoryInfo(path);
foreach (var subdirectory in dirInfo.GetDirectories("*.*", SearchOption.AllDirectories))
{
var item = new SubDirectoryItem()
{
Name = subdirectory.Name,
Path = subdirectory.FullName,
Items = GetSubItems(subdirectory.FullName, SearchOption.AllDirectories)
};
items.Add(item);
}
foreach (var file in dirInfo.GetFiles())
{
var item = new FileItem
{
Name = file.Name,
Path = file.FullName
};
items.Add(item);
}
return items;
}
}
Related
string selectedPath = GetPath();
var subFolders = AssetDatabase.GetSubFolders(selectedPath);
List<string> paths = new List<string>();
foreach(string path in subFolders)
{
paths.Add(path);
}
For example the subFolders is Assets/My Folder
but under My Folder there are many more subfolders.
AssetDatabase.GetSubFolders don't make recursive it's getting the first sub folder only.
I want to get all the sub folders recursive.
I tried :
List paths = new List();
foreach(string path in subFolders)
{
paths.Add(path);
}
but it's still giving me only the first sub folder.
This is how I'm getting the selected path name in the Assets :
[MenuItem("Assets/Get Path")]
private static string GetClickedDirFullPath()
{
string clickedAssetGuid = Selection.assetGUIDs[0];
string clickedPath = AssetDatabase.GUIDToAssetPath(clickedAssetGuid);
string clickedPathFull = Path.Combine(Directory.GetCurrentDirectory(), clickedPath);
FileAttributes attr = File.GetAttributes(clickedPathFull);
return attr.HasFlag(FileAttributes.Directory) ? clickedPathFull : Path.GetDirectoryName(clickedPathFull);
}
[MenuItem("Assets/Get Path")]
private static string GetPath()
{
string path = GetClickedDirFullPath();
int index = path.IndexOf("Assets");
string result = path.Substring(index);
return result;
}
You could simply make it recursive using List<T>.AddRange like
private static string[] GetSubFoldersRecursive(string root)
{
var paths = new List<string>();
// If there are no further subfolders then AssetDatabase.GetSubFolders returns
// an empty array => foreach will not be executed
// This is the exit point for the recursion
foreach (var path in AssetDatabase.GetSubFolders(root))
{
// add this subfolder itself
paths.Add(path);
// If this has no further subfolders then simply no new elements are added
paths.AddRange(GetSubFoldersRecursive(path));
}
return paths.ToArray();
}
So e.g.
[ContextMenu("Test")]
private void Test()
{
var sb = new StringBuilder();
var folders = SubFolders("Assets");
if(folders.Length > 0)
{
foreach (var folder in SubFolders("Assets"))
{
sb.Append(folder).Append('\n');
}
}
else
{
sb.Append(" << The given path has no subfolders! >>");
}
Debug.Log(sb.ToString());
}
will print out the entire project's folder structure.
For
I get
Assets/Example 1
Assets/Example 1/SubFolder A
Assets/Example 1/SubFolder B
Assets/Example 1/SubFolder C
Assets/Example 2
Assets/Example 2/SubFolder A
Assets/Example 2/SubFolder A/SubSubFolder A
So in your case it would be
string selectedPath = GetPath();
var folders = SubFolders(selectedPath);
foreach(var path in folders)
{
...
}
Try this code for get recursive folder path
//this is your code
string selectedPath = GetPath();
var subFolders = AssetDatabase.GetSubFolders(selectedPath);
List<string> paths = new List<string>();
if(subFolders != null)
{
foreach(string path in subFolders)
{
GetAllRecursiveFolder(path,ref paths);
}
}
else
{
paths.add(selectedPath);
}
public void GetAllRecursiveFolder(string currentPath,ref List<string> paths)
{
var subFolders = AssetDatabase.GetSubFolders(currentPath);
if(subFolders != null)
{
foreach(string path in subFolders)
{
GetAllRecursiveFolder(path,ref paths);// Get recursive folder path, and stored in ref variable
}
}
else
{
paths.add(currentPath);
}
}
I have this code
public List<string> GetAllFilesFromFolder(string root, bool searchSubfolders)
{
Queue<string> folders = new Queue<string>();
List<string> files = new List<string>();
folders.Enqueue(root);
while (folders.Count != 0)
{
string currentFolder = folders.Dequeue();
try
{
string[] filesInCurrent = System.IO.Directory.GetFiles(currentFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
files.AddRange(filesInCurrent);
}
catch
{
// Do Nothing
}
try
{
if (searchSubfolders)
{
string[] foldersInCurrent = System.IO.Directory.GetDirectories(currentFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
foreach (string _current in foldersInCurrent)
{
folders.Enqueue(_current);
}
}
}
catch
{
// Do Nothing
}
}
return files;
}
It list all files from especific directory and search for subdirectories ignoring excepetions to a List<string>
But How can I list the List<string> results to a listbox?
I tried to put
foreach (var foo in files)
{
listbox1.Items.Add(foo);
}
after return files; but for some reason the appears nothing in listbox... I am using visual basic windows forms
Try
listBox1.DataSource = MyList;
(duplicate: C#: easiest way to populate a ListBox from a List)
i am new with Nodes here.. :) i came up with this algorithm but it only shows the list of parent nodes.. like this..
a
a.txt
b
c
c
m
n
b
o
p
etc...
i want the next node will be put in one of the node inside the previous node.. so it will come up like this..
a
a.txt
b
o
p
c
m
n
etc...
i have some ideas in mind but i can implement it to codes.. :) any help please..
private void ListDirectory(TreeView treeView, String path)
{
Stack<string> stack = new Stack<string>();
TreeNode DirFilesCollection = new TreeNode();
stack.Push(path);
while (stack.Count > 0)
{
string dir = stack.Pop();
try
{
List<String> parentDir = new List<string>();
parentDir.AddRange(Directory.GetFiles(dir, "*.*"));
parentDir.AddRange(Directory.GetDirectories(dir));
DirectoryInfo d = new DirectoryInfo(dir);
TreeNode TParent = new TreeNode(d.Name);
foreach (String s in parentDir)
{
FileInfo f = new FileInfo(s);
TreeNode subItems = new TreeNode(f.Name);
TParent.Nodes.Add(subItems);
}
DirFilesCollection.Nodes.Add(TParent);
foreach (string dn in Directory.GetDirectories(dir))
{
stack.Push(dn);
}
}
catch
{}
}
Action clearTreeView = () => treeView.Nodes.Clear();
this.Invoke(clearTreeView);
Action showTreeView = () => treeView.Nodes.Add(DirFilesCollection);
this.Invoke(showTreeView);
}
Option #1: Recursive approach:
private void ListDirectory(TreeView treeView, string path)
{
treeView.Nodes.Clear();
var rootDirectoryInfo = new DirectoryInfo(path);
treeView.Nodes.Add(CreateDirectoryNode(rootDirectoryInfo));
}
private static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeNode(directoryInfo.Name);
foreach (var directory in directoryInfo.GetDirectories())
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
foreach (var file in directoryInfo.GetFiles())
directoryNode.Nodes.Add(new TreeNode(file.Name));
return directoryNode;
}
Option #2: Non-recursive approach:
private static void ListDirectory(TreeView treeView, string path)
{
treeView.Nodes.Clear();
var stack = new Stack<TreeNode>();
var rootDirectory = new DirectoryInfo(path);
var node = new TreeNode(rootDirectory.Name) { Tag = rootDirectory };
stack.Push(node);
while (stack.Count > 0)
{
var currentNode = stack.Pop();
var directoryInfo = (DirectoryInfo)currentNode.Tag;
foreach (var directory in directoryInfo.GetDirectories())
{
var childDirectoryNode = new TreeNode(directory.Name) { Tag = directory };
currentNode.Nodes.Add(childDirectoryNode);
stack.Push(childDirectoryNode);
}
foreach (var file in directoryInfo.GetFiles())
currentNode.Nodes.Add(new TreeNode(file.Name));
}
treeView.Nodes.Add(node);
}
I want to collect the directory listing in a collection(a List<> perhaps)
my directory structure is like :
MainFolder\ParentFolder1\SubFolder1
\SubFolder2
\SubFolder3
MainFolder\ParentFolder2\SubFolder1
\SubFolder2
\SubFolder3
I want to list all the subfolders mapped to their parent directories.
Also, the records will have index of ParentFolder 0-n in MainFolder and index of SubFolder 0-n in each ParentFolder.
I did tried below but not yet achieved
lstParents = (from f in Directory.GetDirectories(MainFolder)
select Data
{
parent =f
}).ToList();
var lstSubDir = (from f in lstParents.Select(m => Directory.GetDirectories(m.parent).ToList());
You can use this overload of the GetDirectories method to find all subdirectories recursively:
var mainDirectory = new DirectoryInfo(#"C:\temp\MainFolder");
var subDirectories = mainDirectory.GetDirectories("*", SearchOption.AllDirectories);
Then you can map them into pairs of directory/parent like this:
var mappedDirectories = subDirectories.Select(sd => new { Parent=sd.Parent, Child=sd });
If you want to exclude the first level of subdirectories (ParentFolder1 and ParentFolder2, in your case) you can filter them like this:
var mappedDirectories = subDirectories
.Where(sd => sd.Parent.FullName != mainDirectory.FullName)
.Select(sd => new { Parent=sd.Parent, Child=sd });
EDIT after you've asked for indices:
You stated, that you'll always only have a nesting level of 2, the following piece of code will not work for deeper directory structures.
var mainDirectory = new DirectoryInfo(#"C:\temp\MainFolder");
var firstLevelDirectories = mainDirectory.GetDirectories().Select((f1,i) => new {
Parent = f1,
ParentIndex = i
});
var secondLevelDirectories = firstLevelDirectories
.SelectMany(f1 => f1.Parent.GetDirectories().Select((f2,i) => new {
f1.Parent,
f1.ParentIndex,
Child = f2,
ChildIndex = i
} ));
This will give you a list of records, each containing
the parent directory,
the parent directory index,
the child directory and
the child directory index within its parent.
Try this recursive algorithm.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Folders folders = new Folders(#"c:\temp", null);
Console.ReadLine();
}
}
public class Folders
{
public string path { get; set; }
List<string> files = new List<string>();
List<Folders> folders = new List<Folders>();
Folders parent = null;
public Folders(string path, Folders parent)
{
this.parent = parent;
this.path = path;
foreach (string folderPath in Directory.GetDirectories(path))
{
Folders newFolder = new Folders(folderPath, this);
folders.Add(newFolder);
}
files = Directory.GetFiles(path).ToList();
int pathlength = path.Length;
Boolean first = true;
Console.Write(path);
if (files.Count == 0) Console.WriteLine();
foreach (string file in files)
{
string shortname = file.Substring(file.LastIndexOf("\\") + 1);
if (first)
{
Console.WriteLine("\\" + shortname);
first = false;
}
else
{
Console.WriteLine(new string(' ', pathlength + 1) + shortname);
}
}
}
}
}
I have bunch of directories at a certain paths in the following possible format:
C:\Program Files\Logic\DDC[ 0 ]
C:\Program Files\Logic\DDC[ 1]
C:\Program Files\Logic\DDC[2 ]
C:\Program Files\Logic\DDC[3]
I'd like to accomplish the following:
1)Enumurate all of numbered DDC directories and store their paths them in a List of String
I.E: List<String> ddcPaths -> should have:
ddcPaths[0] = "DDC[0]";
ddcPaths[1] = "DDC[1]";
ddcPaths[2] = "DDC[2]";
2)Enumurate all files directly under the DDC folder but nothing deeper than that
I.E: If DDC[0] has a.txt, b.txt and obj\c.txt, I should get
List<String> ddc_0 -> should have
ddc_0[0] = "a.txt";
ddc_0[1] = "b.txt";
I hope my explanation was clear enough but if something didn't make sense, please let me know.
If U have such data structure I suggest U should use one dictionary with directory name as key, and list of it's filenames as value. For example:
var ddcPaths = new Dictionary<string, List<string>>();
foreach (var directoryInfo in new DirectoryInfo(#"C:\Program Files\Logic\").GetDirectories())
{
if (directoryInfo.Name.Contains("DDC["))
{
ddcPaths.Add(directoryInfo.Name, new List<string>());
foreach (var fileInfo in directoryInfo.GetFiles())
{
ddcPaths[directoryInfo.Name].Add(fileInfo.FullName);
}
}
}
but you should notice than U cant get Dictionary value by int index, only by key, declared in this dictionary (folder name in our case). But if U don't want to do like this U can do the following:
var ddcPaths = new List<string>();
var filePaths = new List<List<string>>();
foreach (var directoryInfo in new DirectoryInfo(#"C:\Program Files\Logic\").GetDirectories())
{
if (directoryInfo.Name.Contains("DDC["))
{
ddcPaths.Add(directoryInfo.Name);
var tempList = new List<string>();
foreach (var fileInfo in directoryInfo.GetFiles())
{
tempList.Add(fileInfo.FullName);
}
filePaths.Add(tempList);
}
}
but in this case U use two different data structures to represent related data. I suggest it would be logically to use dictionary.
You can use DirectoryInfo.
DirectoryInfo dirInfo = new DirectoryInfo("yourFolderPath");
IEnumerable<DirectoryInfo> subDirs = dirInfo.EnumerateDirectories();
List<string> subDirsNames = new List<string>();
foreach (var subDir in subDirs)
{
subDirsNames.Add(subDir.Name.Trim());
IEnumerable<string> files = subDir.EnumerateFiles().Select(i => i.Name);
//do something with this list....
}