Recursive function - Don't show directory if empty - c#

I´m creating a web application that needs to list all the files and directories in a specific folder.
I´ve created the resurvice function to list these, but another specification is that if the directory has no files then the directory shouldn´t be shown.
Now the problem is, what if i have a directory with a submenu, with a submenu, with a submenu, with a submenu and only the last submenu has files in it. It still needs to show all the other directories.
I´ve no idea how to achieve this, any code or tips would be appreciated!
My current recursive function:
private List<FolderModel> GetFolderSubFolders(IFolderInfo folder)
{
var retval = new List<FolderModel>();
// Foreach subfolder in the given folder
foreach (var subFolder in FolderManager.Instance.GetFolders(folder))
{
// Create new foldermodel
var folderModel = new FolderModel
{
FolderName = subFolder.FolderName,
Bestanden = GetFolderBestanden(subFolder),
// Recall this function
SubFolders = GetFolderSubFolders(subFolder)
};
// Check if we have files and subfolders
if (folderModel.Bestanden.Any() && folderModel.SubFolders.Any())
{
folderModel.hasFilesAndFolders = true;
}
retval.Add(folderModel);
}
return retval;
}

Just let it find all directories and then filter for the ones which have files inside:
List<FolderModel> allFolders = GetFolderSubFolders(myFolder);
List<FolderModel> nonEmptyFolders = allFolders.Where(f => f.HasFiles).ToList();

I've not tried to run this but I think something like that should work:
private List<FolderModel> GetFolderSubFolders(IFolderInfo folder)
{
var retval = new List<FolderModel>();
// Foreach subfolder in the given folder
foreach (var subFolder in FolderManager.Instance.GetFolders(folder))
{
// Recall this function
List<FolderModel> subFolders = GetFolderSubFolders(subFolder);
// I am assuming that "Bestanden" is also a List<T> and contains
// the files of this folder
List<Something> bestanden = GetFolderBestanden(subFolder);
// Don't do anything if an empty list was returned
if(subFolders.Count > 0 || bestanden.Count > 0)
{
// Create new foldermodel
var folderModel = new FolderModel
{
FolderName = subFolder.FolderName,
Bestanden = bestanden,
SubFolders = subFolders
};
// Check if we have files and subfolders
if (folderModel.Bestanden.Any() && folderModel.SubFolders.Any())
{
folderModel.hasFilesAndFolders = true;
}
retval.Add(folderModel);
}
}
// If nothing was found this will return an empty list
return retval;
}
The idea is that you don't return anything if you don't find something at the last level. The above may not work as I've not run it but you may get a hint.

Related

Check directory structure

I'm trying to check whether a directory is in a format of
Ex:
This should be valid:
D:\TESTDIR\FOLDER1\FOLDER2\Somerandomfiles
This is not valid:
D:\TESTDIR\FOLDER1\Somerandomfiles
Basically I need to make sure that for every folder there should be a subfolder inside. note that a single folder may contain multiple subfolder. Then the subfolder will contain the files such as text files/pdf files etc.
//not sure how/where to place to check if folder has a subfolder
var _dir = Directory.GetDirectories(#"D:\TESTDIR");
foreach(var _folder1 in _dir)
{
// check if contains folder2? if not
// MessageBox.Show(folder1name);
var _folder2 = Directory.GetDirectories(_folder1);
foreach (var _path in _folder2)
{
// do something
}
}
You almost got it right, I just modified your code a little:
var dir = Directory.GetDirectories(#"D:\TESTDIR");
foreach(var folder1 in dir)
{
var folder2 = Directory.GetDirectories(folder1);
// If no directories are found in that subfolder, skip it.
// Basically it would work the same without if, as loop
// would not run even one iteration, but it's more readable.
if(folder2.Count == 0) continue;
foreach (var path in folder2)
{
var files = Directory.GetFiles(path);
// Same as above, check if there are any files.
if(files.Count == 0) break;
// Do some work
}
}
Here's how I would start this:
var query =
from dir in Directory.GetDirectories(#"D:\TESTDIR")
select new
{
dir,
valid =
Directory.GetDirectories(dir).Any()
&& Directory.GetDirectories(dir).All(child => Directory.GetFiles(child).Any())
};
That's going to check each of the directories in #"D:\TESTDIR" and ensure each has at least one subfolder and that each subfolder has at least one file.

Create nested directories in OneDriveForBusiness using GraphServiceClient

I have been trying to leverage the Microsoft Graph Api to communicate with user's one drive business inside a MVC web app, have set up everything with delegated permissions and can read and write data in logged-in user's ODB fine however is there any way by which nested folder or directory structure can be created?
Currently I am using code below to create the folder in the root of user's ODB and works fine but looking for a way to create hierarchy of the folders when path is provided before uploading the file in it.
DriveItem rootDirectory = graphServiceClient.Me.Drive.Root.Children.Request().AddAsync(new DriveItem
{
Name = "RootDirectory",
Folder = new Folder(),
}).Result;
And for another folder inside RootDirectory trying this but does not seem to work (where rootDirectory is object created above)
DriveItem subDirectory = graphServiceClient.Me.Drive.Root.Children.Request().AddAsync(new DriveItem
{
Name = "SubDirectory",
Folder = rootDirectory.Folder
}).Result;
Even if it works with some fix, not sure if it is most optimal way to do it, suggestions will be appreciated.
I made a small function to do that.
While it is true that the use of try-catch is not the best practice, in the end I think it is better than polling each folder recursively for its children, then lookup by name if part of the path is there.
public async Task CreateFolder(string foldername)
{
string[] splitted = foldername.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
var f = graphServiceClient.Me.Drive.Root;
string p = "";
IDriveItemRequestBuilder b;
DriveItem driveItem;
foreach (string folder in splitted)
{
p = string.Format("{0}{1}{2}", p, string.IsNullOrEmpty(p) ? "" : "/", folder);
b = graphServiceClient.Me.Drive.Root.ItemWithPath(p);
try
{
driveItem = await b.Request().GetAsync();
}
catch
{
driveItem = null;
}
if (driveItem == null)
{
var f2 = await f.Children.Request().AddAsync(new DriveItem()
{
Name = folder,
Folder = new Folder()
});
b = graphServiceClient.Me.Drive.Root.ItemWithPath(p);
}
f = b;
}
}
and you call is like this:
await CreateFolder("folder1/folder2/folder3");
but looking for a way to create hierarchy of the folders when path is provided before uploading the file in it.
Based on my experience hierarchy of the folders is not supported by graphServiceClient currently.
If want to create a sub folder, it requires that parent folder is exist.
As a workaround, we could create the sub folder with following code. You also create a
recursive function to create the nested function
var folder= graphserviceClient.Me.Drive.Root.Children.Request()
.AddAsync(new DriveItem
{
Name = "tomfolder",
Folder = new Folder()
}).Result;
var subfolder = graphserviceClient.Me.Drive.Items[folder.Id].Children.Request()
.AddAsync(new DriveItem
{
Name = "subfolder",
Folder = new Folder()}
).Result;
And you also could give your good ideas to azure team.
I revisited the answer of Pic Mickael because it doesn't work for me (it just create two subfolders).
What I do is to create the first folder of my path so I have a start folder.
If I don't do this, when I try to add the drive item with an empty path I get an error.
So, let's create a root folder, first:
private static void CreateRootFolder(GraphServiceClient gc, string rootFolder)
{
var root = gc
.Drives[_driveId]
.Root
.Children
.Request()
.AddAsync(new DriveItem()
{
Name = rootFolder,
Folder = new Microsoft.Graph.Folder(),
AdditionalData = new Dictionary<string, object>
{
{
"#microsoft.graph.conflictBehavior", "replace"
}
}
})
.Result;
}
When I have my first folder, I can loop through all the others:
private static void CreateSubFolders(GraphServiceClient gc, string rootFolder, string foldername)
{
string[] splitted = foldername.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
string pathCompleto = rootFolder;
foreach (string folder in splitted)
{
var driveItem = new DriveItem
{
Name = folder,
Folder = new Microsoft.Graph.Folder(),
AdditionalData = new Dictionary<string, object>
{
{
"#microsoft.graph.conflictBehavior", "replace"
}
}
};
var newFolder = gc
.Drives[_driveId]
.Root
.ItemWithPath(pathCompleto)
.Children
.Request()
.AddAsync(driveItem)
.Result;
pathCompleto = string.Format("{0}{1}{2}", pathCompleto, string.IsNullOrEmpty(pathCompleto) ? "" : "/", folder);
}
In the main program I will have two calls like this:
CreateRootFolder(_graphClient, "Folder00");
CreateSubFolders(_graphClient, "Folder00", "FolderAA/FolderBB/FolderCC/FolderDD/FolderEE");
This could be improved, but in my case it nicely resolve the problem.

How to get list of files from recycle bin for the volume/disk that was mounted?

Usually people get list of files inside the Recycle Bin using Shell32.dll.
private static IEnumerable<string> GetRecycleBinFilenames()
{
const int ssfBitbucket = 10;
Type t = Type.GetTypeFromProgID("Shell.Application");
dynamic shell = Activator.CreateInstance(t);
Folder recycleBin = shell.NameSpace(ssfBitbucket);
foreach (FolderItem2 recfile in recycleBin.Items())
{
yield return recfile.Path;
}
Marshal.FinalReleaseComObject(shell);
}
I am mounting a VHDX file and want to get a list of files from the Recycle Bin on a mounted external disk/volume. How can I do this?
As #RaymondChen suggested you can filter based on the Path property, which contains the current path of the deleted item...
foreach (FolderItem2 recfile in recycleBin.Items())
{
if (Path.GetPathRoot(recfile.Path) == "X:\\")
yield return recfile.Path;
}
You could also retrieve the path of the directory from which the item was deleted and filter the same way...
const int BitBucketItem_OriginalParentPath = 1;
foreach (FolderItem2 recfile in recycleBin.Items())
{
string originalParentPath = recycleBin.GetDetailsOf(recfile, BitBucketItem_OriginalParentPath);
if (Path.GetPathRoot(originalParentPath) == "X:\\")
yield return recfile.Path;
}
...however if the item was deleted through a junction/symlink then originalParentPath will contain the drive of the junction/symlink, which is not necessarily the drive storing the deleted item.

How do I delete all files in an Azure File Storage folder?

I'm trying to work how how to delete all files in a folder in Azure File Storage.
CloudFileDirectory.ListFilesAndDirectories() returns an IEnumerable of IListFileItem. But this doesn't help much because it doesn't have a filename property or similar.
This is what I have so far:
var folder = root.GetDirectoryReference("myfolder");
if (folder.Exists()) {
foreach (var file in folder.ListFilesAndDirectories()) {
// How do I delete 'file'
}
}
How can I change an IListFileItem to a CloudFile so I can call myfile.Delete()?
ListFilesAndDirectories can return both files and directories so you get a base class for those two. Then you can check which if the types it is and cast. Note you'll want to track any sub-directories so you can recursively delete the files in those.
var folder = root.GetDirectoryReference("myfolder");
if (folder.Exists())
{
foreach (var item in folder.ListFilesAndDirectories())
{
if (item.GetType() == typeof(CloudFile))
{
CloudFile file = (CloudFile)item;
// Do whatever
}
else if (item.GetType() == typeof(CloudFileDirectory))
{
CloudFileDirectory dir = (CloudFileDirectory)item;
// Do whatever
}
}
}
Took existing answers, fixed some bugs and created an extension method to delete the directory recursively
public static async Task DeleteAllAsync(this ShareDirectoryClient dirClient) {
await foreach (ShareFileItem item in dirClient.GetFilesAndDirectoriesAsync()) {
if (item.IsDirectory) {
var subDir = dirClient.GetSubdirectoryClient(item.Name);
await subDir.DeleteAllAsync();
} else {
await dirClient.DeleteFileAsync(item.Name);
}
}
await dirClient.DeleteAsync();
}
Call it like
var dirClient = shareClient.GetDirectoryClient("test");
await dirClient.DeleteAllAsync();
This recursive version works if you have 'directories' inside your 'directory'
public void DeleteOutputDirectory()
{
var share = _fileClient.GetShareReference(_settings.FileShareName);
var rootDir = share.GetRootDirectoryReference();
DeleteDirectory(rootDir.GetDirectoryReference("DirName"));
}
private static void DeleteDirectory(CloudFileDirectory directory)
{
if (directory.Exists())
{
foreach (IListFileItem item in directory.ListFilesAndDirectories())
{
switch (item)
{
case CloudFile file:
file.Delete();
break;
case CloudFileDirectory dir:
DeleteDirectory(dir);
break;
}
}
directory.Delete();
}
}
This implementation would be very easy to achieve with Recursion in PowerShell. Where you specify the directory [can be the root directory in your case] and then all contents of that directory including all files, subdirectories gets deleted. Refer to the github ready PowerShell for the same - https://github.com/kunalchandratre1/DeleteAzureFilesDirectoriesPowerShell
This method should do the trick - please comment if I'm wrong or it could be improved in any way.
public async override Task DeleteFolder(string storagePath)
{
var remaining = new Queue<ShareDirectoryClient>();
remaining.Enqueue(Share.GetDirectoryClient(storagePath));
while(remaining.Count > 0)
{
ShareDirectoryClient dir = remaining.Dequeue();
await foreach (ShareFileItem item in dir.GetFilesAndDirectoriesAsync())
{
if(item.IsDirectory)
{
var subDir = dir.GetSubdirectoryClient(item.Name);
await DeleteFolder(subDir.Path);
}
else
{
await dir
.GetFileClient(item.Name)
.DeleteAsync();
}
}
await dir.DeleteAsync();
}
}
Connect to your Azure container with a Virtual Machine (if file share, then go to fileshare > connect > and follow the commands to paste in your virtual machine - to connect to file share)
Connect to your container in the virtual machine command interface (cd 'location of your container')
Delete the folder (rm -rf 'folder to be deleted')
The accepted answer seems outdated now. The following snippet uses the latest sdk. To have a better performance It's implemented as a for loop not a recursive algorithm. It discovers all files and folders which are located at directoryPath. Once a file is discovered you can delete it.
var rootDirectory = directoryPath != null
? shareClient.GetDirectoryClient(directoryPath)
: shareClient.GetRootDirectoryClient();
var remaining = new Queue<ShareDirectoryClient>();
remaining.Enqueue(rootDirectory);
while (remaining.Count > 0)
{
var shareDirectoryClient = remaining.Dequeue();
await foreach (var item in shareDirectoryClient.GetFilesAndDirectoriesAsync())
{
if (!item.IsDirectory)
{
var shareFileClient = shareDirectoryClient.GetFileClient(item.Name);
files.Add(shareFileClient);
// do what you want
await shareFile.DeleteAsync();
}
if (item.IsDirectory)
{
remaining.Enqueue(shareDirectoryClient.GetSubdirectoryClient(item.Name));
// do what you want
await shareFile.DeleteAsync();
}
}
}
In the above code directory may be null or a path to a directory that you want to delete.
To Initialize the client, you can use the following method:
AccountSasBuilder sas = new AccountSasBuilder
{
Services = AccountSasServices.Files,
ResourceTypes = AccountSasResourceTypes.All,
ExpiresOn = DateTimeOffset.UtcNow.AddMonths(1)
};
sas.SetPermissions(AccountSasPermissions.List | AccountSasPermissions.Read | AccountSasPermissions.Delete);
var credential = new StorageSharedKeyCredential(AccountName, AccountKey);
var sasUri = new UriBuilder(AccountUri);
sasUri.Query = sas.ToSasQueryParameters(credential).ToString();
var shareServiceClient = new ShareServiceClient(sasUri.Uri);
var shareClient = shareServiceClient.GetShareClient(FileShareName);

Delete Folder if it is Empty using C#

I am writing a tool that will allow me to go though a fairly large list of Directories and Sub-directories. I would like it to delete a folder if there it is empty. I can delete folders and sub folders that are empty with this code:
string dir = textBox1.Text;
string[] folders = System.IO.Directory.GetDirectories(dir, "*.*", System.IO.SearchOption.AllDirectories);
foreach (var directory in folders)
{
if (System.IO.Directory.GetFiles(directory).Length == 0 && System.IO.Directory.GetDirectories(directory).Length == 0)
{
System.IO.StreamWriter Dfile = new System.IO.StreamWriter(newpath, true);
System.IO.Directory.Delete(directory);
}
}
My question is how to have the code go though and check the folders after each delete because once it deletes a folder it could make the parent folder empty and should then should be deleted. Once the code does not find any folders or sub-folders that are empty it would exit.
Write a depth-first recursive function. As you complete each recursive call, check the current folder to see if it is empty. If it is, then delete it.
Something like this (pseudocode)
DeleteEmptyFolders(path)
{
foreach Folder f in Path
{
DeleteEmptyFolders(f);
if (f is empty)
{
Delete(f);
}
}
}
You can do this recursively like this (not tested):
void DeleteFolder(string folder) {
string[] folders = System.IO.Directory.GetDirectories(folder, "*.*", System.IO.SearchOption.AllDirectories);
foreach (var directory in folders)
{
DeleteFolder(directory);
}
//delete this folder if empty
}
Here's an idea (this isn't tested)
while ( true )
{
DirectoryInfo parent = Directory.GetParent(current.FullName);
if ( parent.GetFiles().Length == 0 && parent.GetDirectories().Length == 0 )
{
current = parent;
current.Delete();
}
else
{
break;
}
}
This walks up the tree of the current directory to delete any parent directories that are empty.
By the look of it your are trying to delete any folder which does not contain a file. I believe this would do the trick for you. I tested it with a small folder set that went 5 levels deep and a single file in a couple of locations. All folders which did not have files were deleted. All files were left intact. Small tweak to a snippet found... Thanks Matt Smith.
Cannot delete directory with Directory.Delete(path, true)
string[] dirs = System.IO.Directory.GetDirectories(Directory.GetCurrentDirectory(), "*.*",SearchOption.AllDirectories);
foreach (string d in dirs)
{
if (System.IO.Directory.Exists(d)) {
if (System.IO.Directory.GetFiles(d, "*.*", SearchOption.AllDirectories).Length == 0)
{
DeleteDirectory(d);
}
}
}
public static void DeleteDirectory(string target_dir)
{
string[] dirs = Directory.GetDirectories(target_dir);
foreach (string dir in dirs)
{
DeleteDirectory(dir);
}
Directory.Delete(target_dir, false);
}
this will delete all empty (sub)folders in a given directory
https://stackoverflow.com/a/16688997/2408998

Categories

Resources