Program goes through directories and prints Avi files to textbox
public FileList()
{
InitializeComponent();
//Sets Drive Choices
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo d in drives)
{
driveChoice.Items.Add(d);
}
}
//Find Video Files
private void btnStart_Click(object sender, EventArgs e)
{
String path = driveChoice.Text;
if (path != "C:\\")
{
String[] allfiles = Directory.GetFiles(path, "*.avi*", System.IO.SearchOption.AllDirectories);
foreach (String file in allfiles)
{
tbFileList.Text = tbFileList.Text + file + "\r\n";
}
}
else
{
Application.Exit();
}
}
}
When ran I get an error.
Unauthorized Access 'I:\$RECYCLE.BIN\S-1-5-21-1332477098-3306142970-3529014387-1000\'
Can I set the program to just skip 'I:\$RECYCLE.BIN'
Looks like you need to switch to a recursive solution or some other loop rather than using 'AllDirectories'. That way you can provide some skip logic.
see this link http://support.microsoft.com/kb/303974
and this code snippet from that page:
void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, txtFile.Text))
{
lstFilesFound.Items.Add(f);
}
DirSearch(d);
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
In that code you would just check your sDir for the values you want to skip.
Now there is no way to have the AllDirectories option skip specific directories or ignore exceptions that occur from traversing. You will need to manually search the directory structure and deal with errors that occur
if !filePath.Contains("I:\$RECYCLE.BIN")
Use a lambda statement to exclude the system directories:
public FileList()
{
InitializeComponent();
//Sets Drive Choices
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo d in drives)
{
driveChoice.Items.Add(d);
}
}
//Find Video Files
private void btnStart_Click(object sender, EventArgs e)
{
String path = driveChoice.Text;
if (path != "C:\\")
{
DirectoryInfo root = new DirectoryInfo(path);
var rootFiles = root.GetFiles("*.avi");
var rootDirs = root.GetDirectories("*", SearchOption.TopDirectoryOnly).Where(d => !d.Name.Equals("System Volume Information") && !d.Name.Equals("$RECYCLE.BIN"));
foreach (var file in rootFiles)
{
tbFileList.Text = tbFileList.Text + file.FullName + "\r\n";
}
foreach (var dir in rootDirs)
{
foreach (var dirFile in dir.GetFiles("*.avi", SearchOption.AllDirectories))
{
tbFileList.Text = tbFileList.Text + dirFile.FullName + "\r\n";
}
}
}
else
{
Application.Exit();
}
}
I just tried the usage of the Lambda expression of excluding both folders from the returned string list in VS 2017. I observed something strange. If the lambda expression is directly added to the retrieval of the directories as in the string shown above the list still returns $RECYCLEBIN, however SVI folder is not returned. In order to make the lambda working correctly I needed to separate the 2 actions i.e:
var allDirs = rootDir.GetDirectories("*",SearchOption.TopDirectoryOnly);
var filteredDirs = allDirs.Where(d=> !d.Name.Equals("System Volume Information") && !d.Name.Equals("$RECYCLE.BIN"));
Related
Below is my code to get all files in large directory (Framework 3.5). It run ~ 1 hour, but cannot finish, memory in Task Manager upto 1,600,000K
void ApplyAllFiles(DirectoryInfo dir)
{
String space = " ";
foreach (FileInfo f in dir.GetFiles())
{
try
{
int size = Convert.ToInt32(f.Length / 1024);
if (size > filesize && isFileType(f.FullName) == true)
{
pw.WriteLine(f.LastWriteTime + space + size + space + f.FullName);
}
}
catch
{ }
}
foreach (DirectoryInfo d in dir.GetDirectories())
{
try
{
ApplyAllFiles(d);
}
catch
{
}
}
}
If I use Java code, just 5 min for finish and memory always < 100,000 K. I think C# code maybe has problem (getFiles & getDirectories is not good for large Directory). I hope someone can help.
I SOLVED IT BY TAKE FOREACH LOOP INSIDE TRY { }.
You can create a non-recursive extension method:
public static IEnumerable<FileInfo> GetFilesDepthFirst(this DirectoryInfo root,
string dirPattern = "*", string filePattern = "*.*")
{
var stack = new Stack<DirectoryInfo>();
stack.Push(root);
while (stack.Count > 0)
{
var current = stack.Pop();
IEnumerable<FileInfo> files = Enumerable.Empty<FileInfo>();
IEnumerable<DirectoryInfo> dirs = Enumerable.Empty<DirectoryInfo>();
try
{
#if NET35
dirs = current.GetDirectories(searchPattern: dirPattern);
files = current.GetFiles(searchPattern: filePattern);
#else
dirs = current.EnumerateDirectories(searchPattern: dirPattern);
files = current.EnumerateFiles(searchPattern: filePattern);
#endif
}
catch (UnauthorizedAccessException) { }
catch (PathTooLongException) { }
foreach (FileInfo file in files)
yield return file;
foreach (DirectoryInfo dir in dirs)
stack.Push(dir);
}
}
Which you can call like:
var dInfo = new DirectoryInfo("C:\\");
var allFiles = dInfo.GetFilesDepthFirst(filePattern: "*.txt");
foreach(FileInfo file in allFiles)
{
// build output string
}
As other users have stated, Directory.GetFiles is terrible. Directory.EnumerateFiles is an alternative.
Reference from here
I'm a newbish C#er and here's my question:
What I want:
Copy mp3 files of the same Artist into the same Folder.
e.G. Nirvana - Song 1 & Nirvana - Song 2 into Folder "Nirvana".
What I've been doing so far:
Read ParantDirectory and List the ingredients into a Listbox. The Listbox shows only the Artist (of course its filtered(Substring(indexof"-"))). After the files have been read my tool create a Folder with the Artist name.
And there I'm struggling!
I need a snippet that copy all content of Nirvana* to the Nirvana Folder.
I really hope you girls and guys understand what I'm trying to do...
Thank you in advance!
Greetings from Germany,
ceteus
edit:"here's my code"
void Button1Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
DirectoryInfo ParentDirectory = new DirectoryInfo(#"C:\Users\A7024985\Desktop\_xxx");
label1.Text = ParentDirectory.ToString();
foreach (FileInfo f in ParentDirectory.GetFiles())
{
listBox1.Items.Add(f.Name.Substring(0,f.Name.IndexOf("-"))); //nur den Dateinamen anzeigen in Listbox1
//listBox1.Items.Add(f.Name);
}
// DOPPELTE DATEIEN LÖSCHEN in LISTBOX
string[] temp = new string[listBox1.Items.Count];
ArrayList newList = new ArrayList();
for(int i = 0; i< listBox1.Items.Count; i++)
{
temp[i] = listBox1.Items[i].ToString();
}
foreach(string ts in temp)
{
if(!newList.Contains(ts))
{
newList.Add(ts);
}
}
listBox1.Items.Clear();
foreach(string ns in newList)
{
listBox1.Items.Add(ns.ToString());
}
foreach(var listboxitem in listBox1.Items)
{
string pfad = label1.Text + "\\" + listboxitem.ToString();
//DirectoryInfo plop = new DirectoryInfo(name);
//FileInfo[] nPath = plop.GetFiles();
try
{
bool exists = Directory.Exists(pfad);
if(!exists)
{
Directory.CreateDirectory(pfad);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
void Button2Click(object sender, EventArgs e)
{
listBox2.Items.Clear();
DirectoryInfo ParentDirectory = new DirectoryInfo(#"C:\Users\A7024985\Desktop\_xxx");
foreach (FileInfo f in ParentDirectory.GetFiles())
{
listBox2.Items.Add(f.Name.Substring(0,f.Name.IndexOf("-")));
}
foreach(var listboxitem2 in listBox2.Items)
{
string item;
string umbenannt;
File.Copy(#ParentDirectory + "\\" + listboxitem2.ToString(), #ParentDirectory + "\\");
//listBox1.Items.Add(f.Name.Substring(0,f.Name.IndexOf("-")));
}
}
}
I guess you have a List<FileInfo> containing your files? If so you can go with File.Copy like this:
void Button2Click(object sender, EventArgs e)
{
DirectoryInfo ParentDirectory = new DirectoryInfo(#"C:\Users\A7024985\Desktop\");
string interpret = f.Name.Substring(0, f.Name.IndexOf("-")).TrimEnd(' ');
string title = f.Name.Remove(0, interpret.Length+1).TrimStart(' ');
File.Copy(f.FullName, ParentDirectory
+ interpret
+ "\\"
+ title); //or f.Name
}
Copy("C:\Users\A7024985\Desktop\Nirvana-Teen Spirit.mp3" , C:\Users\A7024985\Desktop\Nirvana\Teen Spirit.mp3
A good way to do this is use the TagLib# library (see example here) to find the ID3 tags (Artist, Song, Album, etc...), and then create a collection of these, and then sort them, and then move them to a new folder based on the Artist.
var songList = new List<string>(); //Contains a list of song files. E.g. "Come As You Are.mp3", "Heart Shaped Box.mp3", "Smells Like Teen Spirit.mp3".
var tagLibFiles = new List<TagLib.File>();
tagLibFiles.AddRange(songList.Select(x => new TagLib.File(x));
var nirvanaSongs = tagLibFiles.Where(x => x.Tag.FirstAlbumArtist == "Nirvana").ToList();
foreach(var song in nirvanaSongs)
{
//Move the file to your Nirvana folder.
}
I am guessing listboxitem.ToString() contains the name of the artist.
Then:
var filestomove = ParentDirectory.GetFiles().Where(f=>f.Name.Contains(listboxitem.ToString()));
foreach(var file in filestomove){
File.Move(file.FullName,pfas+file.Nmae)
}
I have a folder "c:\test" which contains multiple archives. How do I search through all the archives in this folder for a specific file.
This only search a particular archive using ZipPath:
private void button1_Click(object sender, EventArgs e)
{
string zipPath = #"C:\Test\archive1.zip";
string filetosearch = "testfile";
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
var position = entry.Name.IndexOf(filetosearch , StringComparison.InvariantCultureIgnoreCase);
if (position > -1)
{
listView1.Items.Add(entry.Name);
}
}
}
}
Is it possible to search all the archives in this folder i.e archive1 to archive70
You can use the following code:
foreach(var zipPath in Directory.GetFiles("C:\\Test"))
{
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
var position = entry.Name.IndexOf(filetosearch , StringComparison.InvariantCultureIgnoreCase);
if (position > -1)
{
listView1.Items.Add(entry.Name);
}
}
}
}
The code gets all the files in the directory and iterates through them. If you need to filter the files by extension you can check it inside the foreach loop.
You probably want something along the lines of
string[] filePaths = Directory.GetFiles(#"c:\Test\", "*.zip")
Then change you click code to
foreach(var filePath in filePaths){
//your code here for each path
}
You may use following code
string[] filePaths = Directory.GetFiles(#"c:\test", "*.zip");
string filetosearch = "testfile";
foreach (var item in filePaths)
{
string name = Path.GetFileName(item);
if (name.IndexOf(filetosearch, StringComparison.InvariantCultureIgnoreCase) != -1)
{
//item is path of that file
}
}
Using C#, how can I delete all files and folders from a directory, but still keep the root directory?
System.IO.DirectoryInfo di = new DirectoryInfo("YourPath");
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo dir in di.GetDirectories())
{
dir.Delete(true);
}
If your directory may have many files, EnumerateFiles() is more efficient than GetFiles(), because when you use EnumerateFiles() you can start enumerating it before the whole collection is returned, as opposed to GetFiles() where you need to load the entire collection in memory before begin to enumerate it. See this quote here:
Therefore, when you are working with many files and directories, EnumerateFiles() can be more efficient.
The same applies to EnumerateDirectories() and GetDirectories(). So the code would be:
foreach (FileInfo file in di.EnumerateFiles())
{
file.Delete();
}
foreach (DirectoryInfo dir in di.EnumerateDirectories())
{
dir.Delete(true);
}
For the purpose of this question, there is really no reason to use GetFiles() and GetDirectories().
Yes, that's the correct way to do it. If you're looking to give yourself a "Clean" (or, as I'd prefer to call it, "Empty" function), you can create an extension method.
public static void Empty(this System.IO.DirectoryInfo directory)
{
foreach(System.IO.FileInfo file in directory.GetFiles()) file.Delete();
foreach(System.IO.DirectoryInfo subDirectory in directory.GetDirectories()) subDirectory.Delete(true);
}
This will then allow you to do something like..
System.IO.DirectoryInfo directory = new System.IO.DirectoryInfo(#"C:\...");
directory.Empty();
The following code will clear the folder recursively:
private void clearFolder(string FolderName)
{
DirectoryInfo dir = new DirectoryInfo(FolderName);
foreach(FileInfo fi in dir.GetFiles())
{
fi.Delete();
}
foreach (DirectoryInfo di in dir.GetDirectories())
{
clearFolder(di.FullName);
di.Delete();
}
}
The simplest way:
Directory.Delete(path,true);
Directory.CreateDirectory(path);
Be aware that this may wipe out some permissions on the folder.
new System.IO.DirectoryInfo(#"C:\Temp").Delete(true);
//Or
System.IO.Directory.Delete(#"C:\Temp", true);
private void ClearFolder(string FolderName)
{
DirectoryInfo dir = new DirectoryInfo(FolderName);
foreach(FileInfo fi in dir.GetFiles())
{
try
{
fi.Delete();
}
catch(Exception) { } // Ignore all exceptions
}
foreach(DirectoryInfo di in dir.GetDirectories())
{
ClearFolder(di.FullName);
try
{
di.Delete();
}
catch(Exception) { } // Ignore all exceptions
}
}
If you know there are no sub-folders, something like this may be the easiest:
Array.ForEach(Directory.GetFiles(folderName), File.Delete);
We can also show love for LINQ:
using System.IO;
using System.Linq;
…
var directory = Directory.GetParent(TestContext.TestDir);
directory.EnumerateFiles()
.ToList().ForEach(f => f.Delete());
directory.EnumerateDirectories()
.ToList().ForEach(d => d.Delete(true));
Note that my solution here is not performant, because I am using Get*().ToList().ForEach(...) which generates the same IEnumerable twice. I use an extension method to avoid this issue:
using System.IO;
using System.Linq;
…
var directory = Directory.GetParent(TestContext.TestDir);
directory.EnumerateFiles()
.ForEachInEnumerable(f => f.Delete());
directory.EnumerateDirectories()
.ForEachInEnumerable(d => d.Delete(true));
This is the extension method:
/// <summary>
/// Extensions for <see cref="System.Collections.Generic.IEnumerable"/>.
/// </summary>
public static class IEnumerableOfTExtensions
{
/// <summary>
/// Performs the <see cref="System.Action"/>
/// on each item in the enumerable object.
/// </summary>
/// <typeparam name="TEnumerable">The type of the enumerable.</typeparam>
/// <param name="enumerable">The enumerable.</param>
/// <param name="action">The action.</param>
/// <remarks>
/// “I am philosophically opposed to providing such a method, for two reasons.
/// …The first reason is that doing so violates the functional programming principles
/// that all the other sequence operators are based upon. Clearly the sole purpose of a call
/// to this method is to cause side effects.”
/// —Eric Lippert, “foreach” vs “ForEach” [http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx]
/// </remarks>
public static void ForEachInEnumerable<TEnumerable>(this IEnumerable<TEnumerable> enumerable, Action<TEnumerable> action)
{
foreach (var item in enumerable)
{
action(item);
}
}
}
I used
Directory.GetFiles(picturePath).ToList().ForEach(File.Delete);
for delete the old picture and I don't need any object in this folder
System.IO.Directory.Delete(installPath, true);
System.IO.Directory.CreateDirectory(installPath);
Here is the tool I ended with after reading all posts.
It does
Deletes all that can be deleted
Returns false if some files remain in folder
It deals with
Readonly files
Deletion delay
Locked files
It doesn't use Directory.Delete because the process is aborted on exception.
/// <summary>
/// Attempt to empty the folder. Return false if it fails (locked files...).
/// </summary>
/// <param name="pathName"></param>
/// <returns>true on success</returns>
public static bool EmptyFolder(string pathName)
{
bool errors = false;
DirectoryInfo dir = new DirectoryInfo(pathName);
foreach (FileInfo fi in dir.EnumerateFiles())
{
try
{
fi.IsReadOnly = false;
fi.Delete();
//Wait for the item to disapear (avoid 'dir not empty' error).
while (fi.Exists)
{
System.Threading.Thread.Sleep(10);
fi.Refresh();
}
}
catch (IOException e)
{
Debug.WriteLine(e.Message);
errors = true;
}
}
foreach (DirectoryInfo di in dir.EnumerateDirectories())
{
try
{
EmptyFolder(di.FullName);
di.Delete();
//Wait for the item to disapear (avoid 'dir not empty' error).
while (di.Exists)
{
System.Threading.Thread.Sleep(10);
di.Refresh();
}
}
catch (IOException e)
{
Debug.WriteLine(e.Message);
errors = true;
}
}
return !errors;
}
Every method that I tried, they have failed at some point with System.IO errors. The following method works for sure, even if the folder is empty or not, read-only or not, etc.
ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C rd /s /q \"C:\\MyFolder"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
Using just static methods with File and Directory instead of FileInfo and DirectoryInfo will perform faster. (see accepted answer at What is the difference between File and FileInfo in C#?). Answer shown as utility method.
public static void Empty(string directory)
{
foreach(string fileToDelete in System.IO.Directory.GetFiles(directory))
{
System.IO.File.Delete(fileToDelete);
}
foreach(string subDirectoryToDeleteToDelete in System.IO.Directory.GetDirectories(directory))
{
System.IO.Directory.Delete(subDirectoryToDeleteToDelete, true);
}
}
I know this is an ancient question but this is the (perhaps new) correct answer:
new DirectoryInfo(folder).Delete(true);
Directory.CreateDirectory(folder);
Deletes all recursive and then recreates the folder.
PS - Must have reference using System.IO;
string directoryPath = "C:\Temp";
Directory.GetFiles(directoryPath).ToList().ForEach(File.Delete);
Directory.GetDirectories(directoryPath).ToList().ForEach(Directory.Delete);
The following code will clean the directory, but leave the root directory there (recursive).
Action<string> DelPath = null;
DelPath = p =>
{
Directory.EnumerateFiles(p).ToList().ForEach(File.Delete);
Directory.EnumerateDirectories(p).ToList().ForEach(DelPath);
Directory.EnumerateDirectories(p).ToList().ForEach(Directory.Delete);
};
DelPath(path);
private void ClearFolder(string FolderName)
{
DirectoryInfo dir = new DirectoryInfo(FolderName);
foreach (FileInfo fi in dir.GetFiles())
{
fi.IsReadOnly = false;
fi.Delete();
}
foreach (DirectoryInfo di in dir.GetDirectories())
{
ClearFolder(di.FullName);
di.Delete();
}
}
In Windows 7, if you have just created it manually with Windows Explorer, the directory structure is similar to this one:
C:
\AAA
\BBB
\CCC
\DDD
And running the code suggested in the original question to clean the directory C:\AAA, the line di.Delete(true) always fails with IOException "The directory is not empty" when trying to delete BBB. It is probably because of some kind of delays/caching in Windows Explorer.
The following code works reliably for me:
static void Main(string[] args)
{
DirectoryInfo di = new DirectoryInfo(#"c:\aaa");
CleanDirectory(di);
}
private static void CleanDirectory(DirectoryInfo di)
{
if (di == null)
return;
foreach (FileSystemInfo fsEntry in di.GetFileSystemInfos())
{
CleanDirectory(fsEntry as DirectoryInfo);
fsEntry.Delete();
}
WaitForDirectoryToBecomeEmpty(di);
}
private static void WaitForDirectoryToBecomeEmpty(DirectoryInfo di)
{
for (int i = 0; i < 5; i++)
{
if (di.GetFileSystemInfos().Length == 0)
return;
Console.WriteLine(di.FullName + i);
Thread.Sleep(50 * i);
}
}
This version does not use recursive calls, and solves the readonly problem.
public static void EmptyDirectory(string directory)
{
// First delete all the files, making sure they are not readonly
var stackA = new Stack<DirectoryInfo>();
stackA.Push(new DirectoryInfo(directory));
var stackB = new Stack<DirectoryInfo>();
while (stackA.Any())
{
var dir = stackA.Pop();
foreach (var file in dir.GetFiles())
{
file.IsReadOnly = false;
file.Delete();
}
foreach (var subDir in dir.GetDirectories())
{
stackA.Push(subDir);
stackB.Push(subDir);
}
}
// Then delete the sub directories depth first
while (stackB.Any())
{
stackB.Pop().Delete();
}
}
The following example shows how you can do that. It first creates some directories and a file and then removes them via Directory.Delete(topPath, true);:
static void Main(string[] args)
{
string topPath = #"C:\NewDirectory";
string subPath = #"C:\NewDirectory\NewSubDirectory";
try
{
Directory.CreateDirectory(subPath);
using (StreamWriter writer = File.CreateText(subPath + #"\example.txt"))
{
writer.WriteLine("content added");
}
Directory.Delete(topPath, true);
bool directoryExists = Directory.Exists(topPath);
Console.WriteLine("top-level directory exists: " + directoryExists);
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.Message);
}
}
It is taken from https://msdn.microsoft.com/en-us/library/fxeahc5f(v=vs.110).aspx.
use DirectoryInfo's GetDirectories method.
foreach (DirectoryInfo subDir in new DirectoryInfo(targetDir).GetDirectories())
subDir.Delete(true);
It's not the best way to deal with the issue above. But it's an alternative one...
while (Directory.GetDirectories(dirpath).Length > 0)
{
//Delete all files in directory
while (Directory.GetFiles(Directory.GetDirectories(dirpath)[0]).Length > 0)
{
File.Delete(Directory.GetFiles(dirpath)[0]);
}
Directory.Delete(Directory.GetDirectories(dirpath)[0]);
}
DirectoryInfo.GetFileSystemInfos returns both files and directories :-
new DirectoryInfo(targetDir).GetFileSystemInfos().ToList().ForEach(x => x.Delete());
or if you want to recursive delete :-
new DirectoryInfo(targetDir).GetFileSystemInfos().ToList().ForEach(x =>
{
if (x is DirectoryInfo di)
di.Delete(true);
else
x.Delete();
});
DirectoryInfo Folder = new DirectoryInfo(Server.MapPath(path));
if (Folder .Exists)
{
foreach (FileInfo fl in Folder .GetFiles())
{
fl.Delete();
}
Folder .Delete();
}
using System.IO;
string[] filePaths = Directory.GetFiles(#"c:\MyDir\");
foreach (string filePath in filePaths)
File.Delete(filePath);
Call from main
static void Main(string[] args)
{
string Filepathe =<Your path>
DeleteDirectory(System.IO.Directory.GetParent(Filepathe).FullName);
}
Add this method
public static void DeleteDirectory(string path)
{
if (Directory.Exists(path))
{
//Delete all files from the Directory
foreach (string file in Directory.GetFiles(path))
{
File.Delete(file);
}
//Delete all child Directories
foreach (string directory in Directory.GetDirectories(path))
{
DeleteDirectory(directory);
}
//Delete a Directory
Directory.Delete(path);
}
}
foreach (string file in System.IO.Directory.GetFiles(path))
{
System.IO.File.Delete(file);
}
foreach (string subDirectory in System.IO.Directory.GetDirectories(path))
{
System.IO.Directory.Delete(subDirectory,true);
}
To delete the folder, this is code using Text box and a button using System.IO; :
private void Deletebt_Click(object sender, EventArgs e)
{
System.IO.DirectoryInfo myDirInfo = new DirectoryInfo(#"" + delete.Text);
foreach (FileInfo file in myDirInfo.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo dir in myDirInfo.GetDirectories())
{
dir.Delete(true);
}
}
In my Case
var PhotoFile = _context.Records.Where(x => id_or_ids.Contains(x.Id)).Select(x => x.Photo).ToList();
System.IO.DirectoryInfo di = new DirectoryInfo("wwwroot/uploads");
foreach (FileInfo file in di.GetFiles())
{
if (PhotoFile.IndexOf(file.Name) != -1)
{
file.Delete();
}
}
private void ClearDirectory(string path)
{
if (Directory.Exists(path))//if folder exists
{
Directory.Delete(path, true);//recursive delete (all subdirs, files)
}
Directory.CreateDirectory(path);//creates empty directory
}
this will show how we delete the folder and check for it we use Text box
using System.IO;
namespace delete_the_folder
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Deletebt_Click(object sender, EventArgs e)
{
//the first you should write the folder place
if (Pathfolder.Text=="")
{
MessageBox.Show("ples write the path of the folder");
Pathfolder.Select();
//return;
}
FileAttributes attr = File.GetAttributes(#Pathfolder.Text);
if (attr.HasFlag(FileAttributes.Directory))
MessageBox.Show("Its a directory");
else
MessageBox.Show("Its a file");
string path = Pathfolder.Text;
FileInfo myfileinf = new FileInfo(path);
myfileinf.Delete();
}
}
}
I need to delete a directory that contains read-only files. Which approach is better:
Using DirectoryInfo.Delete(), or,
ManagementObject.InvokeMethod("Delete")?
With DirectoryInfo.Delete(), I have to manually turn off the read-only attribute for each file, but ManagementObject.InvokeMethod("Delete") doesn't appear to need to. Is there any situation where one is more preferable to the other?
Sample code (test.txt is read only).
First way:
DirectoryInfo dir = new DirectoryInfo(#"C:\Users\David\Desktop\");
dir.CreateSubdirectory("Test");
DirectoryInfo test = new DirectoryInfo(#"C:\Users\David\Desktop\Test\");
File.Copy(#"C:\Users\David\Desktop\test.txt", #"C:\Users\David\Desktop\Test\test.txt");
File.SetAttributes(#"C:\Users\David\Desktop\Test\test.txt", FileAttributes.Archive);
test.Delete(true);
Second way:
DirectoryInfo dir = new DirectoryInfo(#"C:\Users\David\Desktop\");
dir.CreateSubdirectory("Test");
DirectoryInfo test = new DirectoryInfo(#"C:\Users\David\Desktop\Test\");
File.Copy(#"C:\Users\David\Desktop\test.txt", #"C:\Users\David\Desktop\Test\test.txt");
string folder = #"C:\Users\David\Desktop\Test";
string dirObject = "Win32_Directory.Name='" + folder + "'";
using (ManagementObject managementObject = new ManagementObject(dirObject))
{
managementObject.Get();
ManagementBaseObject outParams = managementObject.InvokeMethod("Delete", null,
null);
// ReturnValue should be 0, else failure
if (Convert.ToInt32(outParams.Properties["ReturnValue"].Value) != 0)
{
}
}
Simplest way of avoiding recursive calls is by utilising the AllDirectories option when getting FileSystemInfos, like so:
public static void ForceDeleteDirectory(string path)
{
var directory = new DirectoryInfo(path) { Attributes = FileAttributes.Normal };
foreach (var info in directory.GetFileSystemInfos("*", SearchOption.AllDirectories))
{
info.Attributes = FileAttributes.Normal;
}
directory.Delete(true);
}
Here is an extension method which sets Attributes to Normal recursively, then deletes the items:
public static void DeleteReadOnly(this FileSystemInfo fileSystemInfo)
{
var directoryInfo = fileSystemInfo as DirectoryInfo;
if (directoryInfo != null)
{
foreach (FileSystemInfo childInfo in directoryInfo.GetFileSystemInfos())
{
childInfo.DeleteReadOnly();
}
}
fileSystemInfo.Attributes = FileAttributes.Normal;
fileSystemInfo.Delete();
}
Try this,
private void DeleteRecursiveFolder(string pFolderPath)
{
foreach (string Folder in Directory.GetDirectories(pFolderPath))
{
DeleteRecursiveFolder(Folder);
}
foreach (string file in Directory.GetFiles(pFolderPath))
{
var pPath = Path.Combine(pFolderPath, file);
FileInfo fi = new FileInfo(pPath);
File.SetAttributes(pPath, FileAttributes.Normal);
File.Delete(file);
}
Directory.Delete(pFolderPath);
}
Another method without the need for recursion.
public static void ForceDeleteDirectory(string path)
{
DirectoryInfo root;
Stack<DirectoryInfo> fols;
DirectoryInfo fol;
fols = new Stack<DirectoryInfo>();
root = new DirectoryInfo(path);
fols.Push(root);
while (fols.Count > 0)
{
fol = fols.Pop();
fol.Attributes = fol.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
foreach (DirectoryInfo d in fol.GetDirectories())
{
fols.Push(d);
}
foreach (FileInfo f in fol.GetFiles())
{
f.Attributes = f.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
f.Delete();
}
}
root.Delete(true);
}
private void DeleteRecursiveFolder(DirectoryInfo dirInfo)
{
foreach (var subDir in dirInfo.GetDirectories())
{
DeleteRecursiveFolder(subDir);
}
foreach (var file in dirInfo.GetFiles())
{
file.Attributes=FileAttributes.Normal;
file.Delete();
}
dirInfo.Delete();
}
The best solution is to mark all the files as non-read only, and then delete the directory.
// delete/clear hidden attribute
File.SetAttributes(filePath, File.GetAttributes(filePath) & ~FileAttributes.Hidden);
// delete/clear archive and read only attributes
File.SetAttributes(filePath, File.GetAttributes(filePath)
& ~(FileAttributes.Archive | FileAttributes.ReadOnly));
Notice that ~ is a Bitwise logical operator which returns the complement of the given binary value. I haven't tested this, but it should work.
Thanks!
I would say that your first approach looks more explicit and readable. The second method smells like reflection, is not type safe and looks weird. The ManagementObject can represent multiple things, so it's not obvious that .InvokeMethod("Delete") actually deletes a directory.
On the surface, using the WMI approach seems more efficient than iterating over the entire file system (assume for example the directory has 10's of thousands of files). But I do not know that WMI also doesn't do iterations. If it does, being closer to the metal (again, assumptions) it should be more efficient.
For elegance, I concede the recursive method is cool.
Performance testing should answer the efficiency question. And either can be elegant if wrapped in an extension method of DirectoryInfo.
Here is another solution that avoids recursion on itself.
public static void DirectoryDeleteAll(string directoryPath)
{
var rootInfo = new DirectoryInfo(directoryPath) { Attributes = FileAttributes.Normal };
foreach (var fileInfo in rootInfo.GetFileSystemInfos()) fileInfo.Attributes = FileAttributes.Normal;
foreach (var subDirectory in Directory.GetDirectories(directoryPath, "*", SearchOption.AllDirectories))
{
var subInfo = new DirectoryInfo(subDirectory) { Attributes = FileAttributes.Normal };
foreach (var fileInfo in subInfo.GetFileSystemInfos()) fileInfo.Attributes = FileAttributes.Normal;
}
Directory.Delete(directoryPath, true);
}
This works by resettings attributes on the folders and files before the delete, so you could just remove the last line for a 'DirectoryResetAttributes' method and use delete separately.
On a related note, while this worked, I then had issues with deleting paths that were 'too long' and ended up using a robocopy solution posted here: C# deleting a folder that has long paths
To follow up on Vitaliy Ulantikov's solution I have supplemented it with a rename/move folder method:
public static void renameFolder(String sourcePath, String targetPath) {
try
{
if (System.IO.Directory.Exists(targetPath))
DeleteFileSystemInfo(new DirectoryInfo(targetPath));
System.IO.Directory.Move(sourcePath, targetPath);
}
catch (Exception ex)
{
Console.WriteLine("renameFolder: " + sourcePath + " " + targetPath + " " + ex.Message);
throw ex;
}
}
private static void DeleteFileSystemInfo(FileSystemInfo fsi) {
fsi.Attributes = FileAttributes.Normal;
var di = fsi as DirectoryInfo;
if (di != null)
{
foreach (var dirInfo in di.GetFileSystemInfos())
{
DeleteFileSystemInfo(dirInfo);
}
}
fsi.Delete();
}
My solution for NET framework 3.5 and for NET framework version 4 and higher:
#region DeleteWithReadOnly
internal static void DeleteWithReadOnly(this DirectoryInfo di)
{
foreach (FileSystemInfo fsi in di.EnumerateFileSystemInfos("*", SearchOption.AllDirectories))
{
fsi.Attributes = FileAttributes.Normal;
}
di.Delete(true);
}
#endregion
#region DeleteWithReadOnlyNET3_5
internal static void DeleteWithReadOnlyNET3_5(this DirectoryInfo di)
{
foreach (FileSystemInfo fsi in di.GetFiles("*", SearchOption.AllDirectories))
{
fsi.Attributes = FileAttributes.Normal;
}
di.Delete(true);
}
#endregion
Usage:
DirectoryInfo di = new DirectoryInfo(#"C:\TMP");
di.DeleteWithReadOnly();