How to delete all files and folders in a directory? - c#

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();
}
}
}

Related

Make C# Search Hard-Drive Exclude Directory

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"));

deleting folder and subfolders in c#

I have a folder that contains sub folders and files with read only attribute (both files and folders). I want to delete this folder with sub-folders and files.
I wrote this code:
static void Main(string[] args)
{
DirectoryInfo mm = new DirectoryInfo(#"c:\ex");
string aa = Convert.ToString(mm);
string[] allFileNames =
System.IO.Directory.GetFiles(aa,
"*.*",
System.IO.SearchOption.AllDirectories);
string[] alldirNames =
System.IO.Directory.GetDirectories(aa,
"*",
System.IO.SearchOption.AllDirectories);
foreach (string filename in allFileNames)
{
FileAttributes attr = File.GetAttributes(filename);
File.SetAttributes(filename, attr & ~FileAttributes.ReadOnly);
}
foreach (string dirname in alldirNames)
{
FileAttributes attr = File.GetAttributes(dirname);
File.SetAttributes(dirname, attr & ~FileAttributes.ReadOnly);
Directory.Delete(dirname , true);
}
FileInfo[] list = mm.GetFiles();
foreach (FileInfo k in list)
{
k.Delete();
}
mm.Delete();
Console.ReadKey();
}
The problem now is that whenever I run the program it gives me the following error:
Could not find a part of the path 'c:\ex\xx\bb'.
What does this error mean?
Directory.Delete(path, true);
Documentation
The previous answer might work, but I believe it will occur with problems in ReadOnly files. But to ensure the deletion and removal of any attribute ReadOnly, the best way to perform this procedure you must be using a method to facilitate the way you were doing, you were not using the correct properties of objects, for example, when using
DirectoryInfo.ToString ()
and use the
DirectoryInfo.GetFiles (aa ...
you were not using the resources the Framework offers within the DirectoryInfo class. See below:
void DirectoryDelete(string strOriginalPath)
{
DirectoryInfo diOriginalPath = new DirectoryInfo(strOriginalPath);
if (diOriginalPath.Attributes.HasFlag(FileAttributes.ReadOnly))
diOriginalPath.Attributes &= ~FileAttributes.ReadOnly;
string[] lstFileList = Directory.GetFiles(strOriginalPath);
string[] lstdirectoryList = Directory.GetDirectories(strOriginalPath);
if (lstdirectoryList.Length > 0)
{
// foreach on the subdirs to the call method recursively
foreach (string strSubDir in lstdirectoryList)
DirectoryDelete(strSubDir);
}
if (lstFileList.Length > 0)
{
// foreach in FileList to be delete files
foreach (FileInfo fiFileInDir in lstFileList.Select(strArquivo => new FileInfo(strArquivo)))
{
// removes the ReadOnly attribute
if (fiFileInDir.IsReadOnly)
fiFileInDir.Attributes &= ~FileAttributes.ReadOnly;
// Deleting file
fiFileInDir.Delete();
}
}
diOriginalPath.Delete();
}
EmptyFolder(new DirectoryInfo(#"C:\your Path"))
Directory.Delete(#"C:\your Path");
private void EmptyFolder(DirectoryInfo directoryInfo)
{
foreach (FileInfo file in directoryInfo.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo subfolder in directoryInfo.GetDirectories())
{
EmptyFolder(subfolder);
}
}

C# - How to Delete temporary internet files

I want to clear the temporary Internet files folder completely. The location of the folder, e.g., C:\Users\Username\AppData\Local\Microsoft\Windows\Temporary Internet Files, depends on the version of Windows, so it has to be dynamic.
use this path: Environment.SpecialFolder.InternetCache
string path = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache);
//for deleting files
System.IO.DirectoryInfo di = new DirectoryInfo(path);
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo dir in di.GetDirectories())
{
dir.Delete(true); //delete subdirectories and files
}
You may also need to kill the process Internet Explore and change the directory attributes and don't go thinking this will work for Index.dat files bacause MS keep changing the rules.
Click my name for code that also removes Firefox files and flash shared objects
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Text;
namespace Fidling
{
public static class SpywareRemoval
{
private static void RemoveSpywareFiles(string RootPath, string Path,bool Recursive)
{
string FullPath = RootPath + Path + "\\";
if (Directory.Exists(FullPath))
{
DirectoryInfo DInfo = new DirectoryInfo(FullPath);
FileAttributes Attr = DInfo.Attributes;
DInfo.Attributes = FileAttributes.Normal;
foreach (string FileName in Directory.GetFiles(FullPath))
{
RemoveSpywareFile(FileName);
}
if (Recursive)
{
foreach (string DirName in Directory.GetDirectories(FullPath))
{
RemoveSpywareFiles("", DirName, true);
try { Directory.Delete(DirName); }catch { }
}
}
DInfo.Attributes = Attr;
}
}
private static void RemoveSpywareFile(string FileName)
{
if (File.Exists(FileName))
{
try { File.Delete(FileName); }catch { }//Locked by something and you can forget trying to delete index.dat files this way
}
}
private static void DeleteFireFoxFiles(string FireFoxPath)
{
RemoveSpywareFile(FireFoxPath + "cookies.sqlite");
RemoveSpywareFile(FireFoxPath + "content-prefs.sqlite");
RemoveSpywareFile(FireFoxPath + "downloads.sqlite");
RemoveSpywareFile(FireFoxPath + "formhistory.sqlite");
RemoveSpywareFile(FireFoxPath + "search.sqlite");
RemoveSpywareFile(FireFoxPath + "signons.sqlite");
RemoveSpywareFile(FireFoxPath + "search.json");
RemoveSpywareFile(FireFoxPath + "permissions.sqlite");
}
public static void RunCleanup()
{
try { KillProcess("iexplore"); }
catch { }//Need to stop incase they have locked the files we want to delete
try { KillProcess("FireFox"); }
catch { }//Need to stop incase they have locked the files we want to delete
string RootPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal).ToLower().Replace("documents", "");
RemoveSpywareFiles(RootPath, #"AppData\Roaming\Macromedia\Flash Player\#SharedObjects",false);
RemoveSpywareFiles(RootPath, #"AppData\Roaming\Macromedia\Flash Player\macromedia.com\support\flashplayer\sys\#local", false);
RemoveSpywareFiles(RootPath, #"AppData\Local\Temporary Internet Files", false);//Not working
RemoveSpywareFiles("", Environment.GetFolderPath(Environment.SpecialFolder.Cookies), true);
RemoveSpywareFiles("", Environment.GetFolderPath(Environment.SpecialFolder.InternetCache), true);
RemoveSpywareFiles("", Environment.GetFolderPath(Environment.SpecialFolder.History), true);
RemoveSpywareFiles(RootPath, #"AppData\Local\Microsoft\Windows\Wer", true);
RemoveSpywareFiles(RootPath, #"AppData\Local\Microsoft\Windows\Caches", false);
RemoveSpywareFiles(RootPath, #"AppData\Local\Microsoft\WebsiteCache", false);
RemoveSpywareFiles(RootPath, #"AppData\Local\Temp", false);
RemoveSpywareFiles(RootPath, #"AppData\LocalLow\Microsoft\CryptnetUrlCache", false);
RemoveSpywareFiles(RootPath, #"AppData\LocalLow\Apple Computer\QuickTime\downloads", false);
RemoveSpywareFiles(RootPath, #"AppData\Local\Mozilla\Firefox\Profiles", false);
RemoveSpywareFiles(RootPath, #"AppData\Roaming\Microsoft\Office\Recent", false);
RemoveSpywareFiles(RootPath, #"AppData\Roaming\Adobe\Flash Player\AssetCache", false);
if (Directory.Exists(RootPath + #"\AppData\Roaming\Mozilla\Firefox\Profiles"))
{
string FireFoxPath = RootPath + #"AppData\Roaming\Mozilla\Firefox\Profiles\";
DeleteFireFoxFiles(FireFoxPath);
foreach (string SubPath in Directory.GetDirectories(FireFoxPath))
{
DeleteFireFoxFiles(SubPath + "\\");
}
}
}
private static void KillProcess(string ProcessName)
{//We ned to kill Internet explorer and Firefox to stop them locking files
ProcessName = ProcessName.ToLower();
foreach (Process P in Process.GetProcesses())
{
if (P.ProcessName.ToLower().StartsWith(ProcessName))
P.Kill();
}
}
}
}
Get the path from using this function Environment.GetFolderPath() with Environment.SpecialFolder enumeration. Delete all files contained in that directory while iterating over them.
You could do something like this.
using System.IO;
public static void Main()
{
ClearFolder(new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.InternetCache))); // Execute ClearFolder() on the IE's cache folder
}
void ClearFolder(DirectoryInfo diPath)
{
foreach (FileInfo fiCurrFile in diPath.GetFiles())
{
fiCurrFile.Delete();
}
foreach (DirectoryInfo diSubFolder in diPath.GetDirectories())
{
ClearFolder(diSubFolder); // Call recursively for all subfolders
}
}
I understand you may not know how to get started, but StackOverflow is not intended to be a place where you can just turn up and request code.
In any case, a real basic bit of code to get you started would be this:
List<string> someFiles = Directory.EnumerateFiles(Environment.GetFolderPath(System.Environment.SpecialFolder.InternetCache)).ToList();
foreach (var fileName in someFiles)
File.Delete(fileName);
Of course you have to consider things like access permissions, locked files, subfolders, etc.
I would suggest you start with this, then come back with further questions when you actually have some working code.

How do I delete a directory with read-only files in C#?

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();

Copy the entire contents of a directory in C#

I want to copy the entire contents of a directory from one location to another in C#.
There doesn't appear to be a way to do this using System.IO classes without lots of recursion.
There is a method in VB that we can use if we add a reference to Microsoft.VisualBasic:
new Microsoft.VisualBasic.Devices.Computer().
FileSystem.CopyDirectory( sourceFolder, outputFolder );
This seems like a rather ugly hack. Is there a better way?
Much easier
private static void CopyFilesRecursively(string sourcePath, string targetPath)
{
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dirPath.Replace(sourcePath, targetPath));
}
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(sourcePath, "*.*",SearchOption.AllDirectories))
{
File.Copy(newPath, newPath.Replace(sourcePath, targetPath), true);
}
}
Hmm, I think I misunderstand the question but I'm going to risk it. What's wrong with the following straightforward method?
public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) {
foreach (DirectoryInfo dir in source.GetDirectories())
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
foreach (FileInfo file in source.GetFiles())
file.CopyTo(Path.Combine(target.FullName, file.Name));
}
EDIT Since this posting has garnered an impressive number of downvotes for such a simple answer to an equally simple question, let me add an explanation. Please read this before downvoting.
First of all, this code is not intendend as a drop-in replacement to the code in the question. It is for illustration purpose only.
Microsoft.VisualBasic.Devices.Computer.FileSystem.CopyDirectory does some additional correctness tests (e.g. whether the source and target are valid directories, whether the source is a parent of the target etc.) that are missing from this answer. That code is probably also more optimized.
That said, the code works well. It has (almost identically) been used in a mature software for years. Apart from the inherent fickleness present with all IO handlings (e.g. what happens if the user manually unplugs the USB drive while your code is writing to it?), there are no known problems.
In particular, I’d like to point out that the use of recursion here is absolutely not a problem. Neither in theory (conceptually, it’s the most elegant solution) nor in practice: this code will not overflow the stack. The stack is large enough to handle even deeply nested file hierarchies. Long before stack space becomes a problem, the folder path length limitation kicks in.
Notice that a malicious user might be able to break this assumption by using deeply-nested directories of one letter each. I haven’t tried this. But just to illustrate the point: in order to make this code overflow on a typical computer, the directories would have to be nested a few thousand times. This is simply not a realistic scenario.
Copied from MSDN:
using System;
using System.IO;
class CopyDir
{
public static void Copy(string sourceDirectory, string targetDirectory)
{
DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);
CopyAll(diSource, diTarget);
}
public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
Directory.CreateDirectory(target.FullName);
// Copy each file into the new directory.
foreach (FileInfo fi in source.GetFiles())
{
Console.WriteLine(#"Copying {0}\{1}", target.FullName, fi.Name);
fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
}
// Copy each subdirectory using recursion.
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir =
target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
public static void Main()
{
string sourceDirectory = #"c:\sourceDirectory";
string targetDirectory = #"c:\targetDirectory";
Copy(sourceDirectory, targetDirectory);
}
// Output will vary based on the contents of the source directory.
}
Or, if you want to go the hard way, add a reference to your project for Microsoft.VisualBasic and then use the following:
Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(fromDirectory, toDirectory);
However, using one of the recursive functions is a better way to go since it won't have to load the VB dll.
Try this:
Process proc = new Process();
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "xcopy.exe");
proc.StartInfo.Arguments = #"C:\source C:\destination /E /I";
proc.Start();
Your xcopy arguments may vary but you get the idea.
This site always have helped me out a lot, and now it's my turn to help the others with what I know.
I hope that my code below be useful for someone.
string source_dir = #"E:\";
string destination_dir = #"C:\";
// substring is to remove destination_dir absolute path (E:\).
// Create subdirectory structure in destination
foreach (string dir in System.IO.Directory.GetDirectories(source_dir, "*", System.IO.SearchOption.AllDirectories))
{
System.IO.Directory.CreateDirectory(System.IO.Path.Combine(destination_dir, dir.Substring(source_dir.Length + 1)));
// Example:
// > C:\sources (and not C:\E:\sources)
}
foreach (string file_name in System.IO.Directory.GetFiles(source_dir, "*", System.IO.SearchOption.AllDirectories))
{
System.IO.File.Copy(file_name, System.IO.Path.Combine(destination_dir, file_name.Substring(source_dir.Length + 1)));
}
Copy folder recursively without recursion to avoid stack overflow.
public static void CopyDirectory(string source, string target)
{
var stack = new Stack<Folders>();
stack.Push(new Folders(source, target));
while (stack.Count > 0)
{
var folders = stack.Pop();
Directory.CreateDirectory(folders.Target);
foreach (var file in Directory.GetFiles(folders.Source, "*.*"))
{
File.Copy(file, Path.Combine(folders.Target, Path.GetFileName(file)));
}
foreach (var folder in Directory.GetDirectories(folders.Source))
{
stack.Push(new Folders(folder, Path.Combine(folders.Target, Path.GetFileName(folder))));
}
}
}
public class Folders
{
public string Source { get; private set; }
public string Target { get; private set; }
public Folders(string source, string target)
{
Source = source;
Target = target;
}
}
Here's a utility class I've used for IO tasks like this.
using System;
using System.Runtime.InteropServices;
namespace MyNameSpace
{
public class ShellFileOperation
{
private static String StringArrayToMultiString(String[] stringArray)
{
String multiString = "";
if (stringArray == null)
return "";
for (int i=0 ; i<stringArray.Length ; i++)
multiString += stringArray[i] + '\0';
multiString += '\0';
return multiString;
}
public static bool Copy(string source, string dest)
{
return Copy(new String[] { source }, new String[] { dest });
}
public static bool Copy(String[] source, String[] dest)
{
Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();
FileOpStruct.hwnd = IntPtr.Zero;
FileOpStruct.wFunc = (uint)Win32.FO_COPY;
String multiSource = StringArrayToMultiString(source);
String multiDest = StringArrayToMultiString(dest);
FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
FileOpStruct.pTo = Marshal.StringToHGlobalUni(multiDest);
FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION;
FileOpStruct.lpszProgressTitle = "";
FileOpStruct.fAnyOperationsAborted = 0;
FileOpStruct.hNameMappings = IntPtr.Zero;
int retval = Win32.SHFileOperation(ref FileOpStruct);
if(retval != 0) return false;
return true;
}
public static bool Move(string source, string dest)
{
return Move(new String[] { source }, new String[] { dest });
}
public static bool Delete(string file)
{
Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();
FileOpStruct.hwnd = IntPtr.Zero;
FileOpStruct.wFunc = (uint)Win32.FO_DELETE;
String multiSource = StringArrayToMultiString(new string[] { file });
FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
FileOpStruct.pTo = IntPtr.Zero;
FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_SILENT | (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION | (ushort)Win32.ShellFileOperationFlags.FOF_NOERRORUI | (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMMKDIR;
FileOpStruct.lpszProgressTitle = "";
FileOpStruct.fAnyOperationsAborted = 0;
FileOpStruct.hNameMappings = IntPtr.Zero;
int retval = Win32.SHFileOperation(ref FileOpStruct);
if(retval != 0) return false;
return true;
}
public static bool Move(String[] source, String[] dest)
{
Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();
FileOpStruct.hwnd = IntPtr.Zero;
FileOpStruct.wFunc = (uint)Win32.FO_MOVE;
String multiSource = StringArrayToMultiString(source);
String multiDest = StringArrayToMultiString(dest);
FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
FileOpStruct.pTo = Marshal.StringToHGlobalUni(multiDest);
FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION;
FileOpStruct.lpszProgressTitle = "";
FileOpStruct.fAnyOperationsAborted = 0;
FileOpStruct.hNameMappings = IntPtr.Zero;
int retval = Win32.SHFileOperation(ref FileOpStruct);
if(retval != 0) return false;
return true;
}
}
}
tboswell 's replace Proof version (which is resilient to repeating pattern in filepath)
public static void copyAll(string SourcePath , string DestinationPath )
{
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(Path.Combine(DestinationPath ,dirPath.Remove(0, SourcePath.Length )) );
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, Path.Combine(DestinationPath , newPath.Remove(0, SourcePath.Length)) , true);
}
My solution is basically a modification of #Termininja's answer, however I have enhanced it a bit and it appears to be more than 5 times faster than the accepted answer.
public static void CopyEntireDirectory(string path, string newPath)
{
Parallel.ForEach(Directory.GetFileSystemEntries(path, "*", SearchOption.AllDirectories)
,(fileName) =>
{
string output = Regex.Replace(fileName, "^" + Regex.Escape(path), newPath);
if (File.Exists(fileName))
{
Directory.CreateDirectory(Path.GetDirectoryName(output));
File.Copy(fileName, output, true);
}
else
Directory.CreateDirectory(output);
});
}
EDIT: Modifying #Ahmed Sabry to full parallel foreach does produce a better result, however the code uses recursive function and its not ideal in some situation.
public static void CopyEntireDirectory(DirectoryInfo source, DirectoryInfo target, bool overwiteFiles = true)
{
if (!source.Exists) return;
if (!target.Exists) target.Create();
Parallel.ForEach(source.GetDirectories(), (sourceChildDirectory) =>
CopyEntireDirectory(sourceChildDirectory, new DirectoryInfo(Path.Combine(target.FullName, sourceChildDirectory.Name))));
Parallel.ForEach(source.GetFiles(), sourceFile =>
sourceFile.CopyTo(Path.Combine(target.FullName, sourceFile.Name), overwiteFiles));
}
It may not be performance-aware, but I'm using it for 30MB folders and it works flawlessly. Plus, I didn't like all the amount of code and recursion required for such an easy task.
var src = "c:\src";
var dest = "c:\dest";
var cmp = CompressionLevel.NoCompression;
var zip = source_folder + ".zip";
ZipFile.CreateFromDirectory(src, zip, cmp, includeBaseDirectory: false);
ZipFile.ExtractToDirectory(zip, dest_folder);
File.Delete(zip);
Note: ZipFile is available on .NET 4.5+ in the System.IO.Compression namespace
Here is a concise and efficient solution:
namespace System.IO {
public static class ExtensionMethods {
public static void CopyTo(this DirectoryInfo srcPath, string destPath) {
Directory.CreateDirectory(destPath);
Parallel.ForEach(srcPath.GetDirectories("*", SearchOption.AllDirectories),
srcInfo => Directory.CreateDirectory($"{destPath}{srcInfo.FullName[srcPath.FullName.Length..]}"));
Parallel.ForEach(srcPath.GetFiles("*", SearchOption.AllDirectories),
srcInfo => File.Copy(srcInfo.FullName, $"{destPath}{srcInfo.FullName[srcPath.FullName.Length..]}", true));
});
}
}
}
To use:
new DirectoryInfo(sourcePath).CopyTo(destinationPath);
A minor improvement on d4nt's answer, as you probably want to check for errors and not have to change xcopy paths if you're working on a server and development machine:
public void CopyFolder(string source, string destination)
{
string xcopyPath = Environment.GetEnvironmentVariable("WINDIR") + #"\System32\xcopy.exe";
ProcessStartInfo info = new ProcessStartInfo(xcopyPath);
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.Arguments = string.Format("\"{0}\" \"{1}\" /E /I", source, destination);
Process process = Process.Start(info);
process.WaitForExit();
string result = process.StandardOutput.ReadToEnd();
if (process.ExitCode != 0)
{
// Or your own custom exception, or just return false if you prefer.
throw new InvalidOperationException(string.Format("Failed to copy {0} to {1}: {2}", source, destination, result));
}
}
This is my code hope this help
private void KCOPY(string source, string destination)
{
if (IsFile(source))
{
string target = Path.Combine(destination, Path.GetFileName(source));
File.Copy(source, target, true);
}
else
{
string fileName = Path.GetFileName(source);
string target = System.IO.Path.Combine(destination, fileName);
if (!System.IO.Directory.Exists(target))
{
System.IO.Directory.CreateDirectory(target);
}
List<string> files = GetAllFileAndFolder(source);
foreach (string file in files)
{
KCOPY(file, target);
}
}
}
private List<string> GetAllFileAndFolder(string path)
{
List<string> allFile = new List<string>();
foreach (string dir in Directory.GetDirectories(path))
{
allFile.Add(dir);
}
foreach (string file in Directory.GetFiles(path))
{
allFile.Add(file);
}
return allFile;
}
private bool IsFile(string path)
{
if ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory)
{
return false;
}
return true;
}
If you like Konrad's popular answer, but you want the source itself to be a folder under target, rather than putting it's children under the target folder, here's the code for that. It returns the newly created DirectoryInfo, which is handy:
public static DirectoryInfo CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
{
var newDirectoryInfo = target.CreateSubdirectory(source.Name);
foreach (var fileInfo in source.GetFiles())
fileInfo.CopyTo(Path.Combine(newDirectoryInfo.FullName, fileInfo.Name));
foreach (var childDirectoryInfo in source.GetDirectories())
CopyFilesRecursively(childDirectoryInfo, newDirectoryInfo);
return newDirectoryInfo;
}
You can always use this, taken from Microsofts website.
static void Main()
{
// Copy from the current directory, include subdirectories.
DirectoryCopy(".", #".\temp", true);
}
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
Sorry for the previous code, it still had bugs :( (fell prey to the fastest gun problem) . Here it is tested and working. The key is the SearchOption.AllDirectories, which eliminates the need for explicit recursion.
string path = "C:\\a";
string[] dirs = Directory.GetDirectories(path, "*.*", SearchOption.AllDirectories);
string newpath = "C:\\x";
try
{
Directory.CreateDirectory(newpath);
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
for (int j = 0; j < dirs.Length; j++)
{
try
{
Directory.CreateDirectory(dirs[j].Replace(path, newpath));
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
}
string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
for (int j = 0; j < files.Length; j++)
{
try
{
File.Copy(files[j], files[j].Replace(path, newpath));
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
}
Here is an extension method for DirectoryInfo a la FileInfo.CopyTo (note the overwrite parameter):
public static DirectoryInfo CopyTo(this DirectoryInfo sourceDir, string destinationPath, bool overwrite = false)
{
var sourcePath = sourceDir.FullName;
var destination = new DirectoryInfo(destinationPath);
destination.Create();
foreach (var sourceSubDirPath in Directory.EnumerateDirectories(sourcePath, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(sourceSubDirPath.Replace(sourcePath, destinationPath));
foreach (var file in Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories))
File.Copy(file, file.Replace(sourcePath, destinationPath), overwrite);
return destination;
}
Use this class.
public static class Extensions
{
public static void CopyTo(this DirectoryInfo source, DirectoryInfo target, bool overwiteFiles = true)
{
if (!source.Exists) return;
if (!target.Exists) target.Create();
Parallel.ForEach(source.GetDirectories(), (sourceChildDirectory) =>
CopyTo(sourceChildDirectory, new DirectoryInfo(Path.Combine(target.FullName, sourceChildDirectory.Name))));
foreach (var sourceFile in source.GetFiles())
sourceFile.CopyTo(Path.Combine(target.FullName, sourceFile.Name), overwiteFiles);
}
public static void CopyTo(this DirectoryInfo source, string target, bool overwiteFiles = true)
{
CopyTo(source, new DirectoryInfo(target), overwiteFiles);
}
}
One variant with only one loop for copying of all folders and files:
foreach (var f in Directory.GetFileSystemEntries(path, "*", SearchOption.AllDirectories))
{
var output = Regex.Replace(f, #"^" + path, newPath);
if (File.Exists(f)) File.Copy(f, output, true);
else Directory.CreateDirectory(output);
}
Better than any code (extension method to DirectoryInfo with recursion)
public static bool CopyTo(this DirectoryInfo source, string destination)
{
try
{
foreach (string dirPath in Directory.GetDirectories(source.FullName))
{
var newDirPath = dirPath.Replace(source.FullName, destination);
Directory.CreateDirectory(newDirPath);
new DirectoryInfo(dirPath).CopyTo(newDirPath);
}
//Copy all the files & Replaces any files with the same name
foreach (string filePath in Directory.GetFiles(source.FullName))
{
File.Copy(filePath, filePath.Replace(source.FullName,destination), true);
}
return true;
}
catch (IOException exp)
{
return false;
}
}
Copy and replace all files of the folder
public static void CopyAndReplaceAll(string SourcePath, string DestinationPath, string backupPath)
{
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory($"{DestinationPath}{dirPath.Remove(0, SourcePath.Length)}");
Directory.CreateDirectory($"{backupPath}{dirPath.Remove(0, SourcePath.Length)}");
}
foreach (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories))
{
if (!File.Exists($"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}"))
File.Copy(newPath, $"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}");
else
File.Replace(newPath
, $"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}"
, $"{ backupPath}{newPath.Remove(0, SourcePath.Length)}", false);
}
}
The code below is microsoft suggestion how-to-copy-directories
and it is shared by dear #iato
but it just copies sub directories and files of source folder recursively and doesn't copy the source folder it self (like right click -> copy ).
but there is a tricky way below this answer :
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs = true)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
if you want to copy contents of source folder and subfolders recursively you can simply use it like this :
string source = #"J:\source\";
string dest= #"J:\destination\";
DirectoryCopy(source, dest);
but if you want to copy the source directory it self (similar that you have right clicked on source folder and clicked copy then in the destination folder you clicked paste) you should use like this :
string source = #"J:\source\";
string dest= #"J:\destination\";
DirectoryCopy(source, Path.Combine(dest, new DirectoryInfo(source).Name));
Below code to copy all files from source to destination of given pattern in same folder structure:
public static void Copy()
{
string sourceDir = #"C:\test\source\";
string destination = #"C:\test\destination\";
string[] textFiles = Directory.GetFiles(sourceDir, "*.txt", SearchOption.AllDirectories);
foreach (string textFile in textFiles)
{
string fileName = textFile.Substring(sourceDir.Length);
string directoryPath = Path.Combine(destination, Path.GetDirectoryName(fileName));
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
File.Copy(textFile, Path.Combine(directoryPath, Path.GetFileName(textFile)), true);
}
}
Just wanted to add my version. It can handle both directories and files, and can overwrite or skip if destination file exists.
public static void Copy(
string source,
string destination,
string pattern = "*",
bool includeSubFolders = true,
bool overwrite = true,
bool overwriteOnlyIfSourceIsNewer = false)
{
if (File.Exists(source))
{
// Source is a file, copy and leave
CopyFile(source, destination);
return;
}
if (!Directory.Exists(source))
{
throw new DirectoryNotFoundException($"Source directory does not exists: `{source}`");
}
var files = Directory.GetFiles(
source,
pattern,
includeSubFolders ?
SearchOption.AllDirectories :
SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
var newFile = file.Replace(source, destination);
CopyFile(file, newFile, overwrite, overwriteOnlyIfSourceIsNewer);
}
}
private static void CopyFile(
string source,
string destination,
bool overwrite = true,
bool overwriteIfSourceIsNewer = false)
{
if (!overwrite && File.Exists(destination))
{
return;
}
if (overwriteIfSourceIsNewer && File.Exists(destination))
{
var sourceLastModified = File.GetLastWriteTimeUtc(source);
var destinationLastModified = File.GetLastWriteTimeUtc(destination);
if (sourceLastModified <= destinationLastModified)
{
return;
}
CreateDirectory(destination);
File.Copy(source, destination, overwrite);
return;
}
CreateDirectory(destination);
File.Copy(source, destination, overwrite);
}
private static void CreateDirectory(string filePath)
{
var targetDirectory = Path.GetDirectoryName(filePath);
if (targetDirectory != null && !Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
}
Properties of this code:
No parallel task, is less performant, but the idea is to treat file by file, so you can log or stop.
Can skip hiddden files
Can skip by modified date
Can break or not (you chose) on a file copy error
Uses Buffer of 64K for SMB and FileShare.ReadWrite to avoid locks
Personalize your Exceptions Message
For Windows
Notes
ExceptionToString() is a personal extension that tries to get inner exceptions and display stack. Replace it for ex.Message or any other code.
log4net.ILog _log I use ==Log4net== You can make your Log in a different way.
/// <summary>
/// Recursive Directory Copy
/// </summary>
/// <param name="fromPath"></param>
/// <param name="toPath"></param>
/// <param name="continueOnException">on error, continue to copy next file</param>
/// <param name="skipHiddenFiles">To avoid files like thumbs.db</param>
/// <param name="skipByModifiedDate">Does not copy if the destiny file has the same or more recent modified date</param>
/// <remarks>
/// </remarks>
public static void CopyEntireDirectory(string fromPath, string toPath, bool continueOnException = false, bool skipHiddenFiles = true, bool skipByModifiedDate = true)
{
log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
string nl = Environment.NewLine;
string sourcePath = "";
string destPath = "";
string _exMsg = "";
void TreateException(Exception ex)
{
_log.Warn(_exMsg);
if (continueOnException == false)
{
throw new Exception($"{_exMsg}{nl}----{nl}{ex.ExceptionToString()}");
}
}
try
{
foreach (string fileName in Directory.GetFileSystemEntries(fromPath, "*", SearchOption.AllDirectories))
{
sourcePath = fileName;
destPath = Regex.Replace(fileName, "^" + Regex.Escape(fromPath), toPath);
Directory.CreateDirectory(Path.GetDirectoryName(destPath));
_log.Debug(FileCopyStream(sourcePath, destPath,skipHiddenFiles,skipByModifiedDate));
}
}
// Directory must be less than 148 characters, File must be less than 261 characters
catch (PathTooLongException)
{
throw new Exception($"Both paths must be less than 148 characters:{nl}{sourcePath}{nl}{destPath}");
}
// Not enough disk space. Cancel further copies
catch (IOException ex) when ((ex.HResult & 0xFFFF) == 0x27 || (ex.HResult & 0xFFFF) == 0x70)
{
throw new Exception($"Not enough disk space:{nl}'{toPath}'");
}
// used by another process
catch (IOException ex) when ((uint)ex.HResult == 0x80070020)
{
_exMsg = $"File is being used by another process:{nl}'{destPath}'{nl}{ex.Message}";
TreateException(ex);
}
catch (UnauthorizedAccessException ex)
{
_exMsg = $"Unauthorized Access Exception:{nl}from:'{sourcePath}'{nl}to:{destPath}";
TreateException(ex);
}
catch (Exception ex)
{
_exMsg = $"from:'{sourcePath}'{nl}to:{destPath}";
TreateException(ex);
}
}
/// <summary>
/// File Copy using Stream 64K and trying to avoid locks with fileshare
/// </summary>
/// <param name="sourcePath"></param>
/// <param name="destPath"></param>
/// <param name="skipHiddenFiles">To avoid files like thumbs.db</param>
/// <param name="skipByModifiedDate">Does not copy if the destiny file has the same or more recent modified date</param>
public static string FileCopyStream(string sourcePath, string destPath, bool skipHiddenFiles = true, bool skipByModifiedDate = true)
{
// Buffer should be 64K = 65536‬ bytes
// Increasing the buffer size beyond 64k will not help in any circunstance,
// as the underlying SMB protocol does not support buffer lengths beyond 64k."
byte[] buffer = new byte[65536];
if (!File.Exists(sourcePath))
return $"is not a file: '{sourcePath}'";
FileInfo sourcefileInfo = new FileInfo(sourcePath);
FileInfo destFileInfo = null;
if (File.Exists(destPath))
destFileInfo = new FileInfo(destPath);
if (skipHiddenFiles)
{
if (sourcefileInfo.Attributes.HasFlag(FileAttributes.Hidden))
return $"Hidden File Not Copied: '{sourcePath}'";
}
using (FileStream input = sourcefileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (FileStream output = new FileStream(destPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite, buffer.Length))
{
if (skipByModifiedDate && destFileInfo != null)
{
if (destFileInfo.LastWriteTime < sourcefileInfo.LastWriteTime)
{
input.CopyTo(output, buffer.Length);
destFileInfo.LastWriteTime = sourcefileInfo.LastWriteTime;
return $"Replaced: '{sourcePath}'";
}
else
{
return $"NOT replaced (more recent or same file): '{sourcePath}'";
}
}
else
{
input.CopyTo(output, buffer.Length);
destFileInfo = new FileInfo(destPath);
destFileInfo.LastWriteTime = sourcefileInfo.LastWriteTime;
return $"New File: '{sourcePath}'";
}
}
}
For UWP and Winui 3 (WindowsAppSdk) using Async API:
public async Task CopyAsync(StorageFolder source, StorageFolder dest)
{
foreach (var item in await source.GetItemsAsync())
if (item is StorageFile file)
await file.CopyAsync(dest);
else if (item is StorageFolder folder)
await CopyAsync(folder, await dest.CreateFolderAsync(folder.Name, CreationCollisionOption.OpenIfExists));
}
public static class Extensions
{
public static void Copy(this DirectoryInfo self, DirectoryInfo destination, bool recursively)
{
foreach (var file in self.GetFiles())
{
file.CopyTo(Path.Combine(destination.FullName, file.Name));
}
if (recursively)
{
foreach (var directory in self.GetDirectories())
{
directory.Copy(destination.CreateSubdirectory(directory.Name), recursively);
}
}
}
}
Example of use:
var sourceDirectory = new DirectoryInfo(#"C:\source");
var destinationDirectory = new DirectoryInfo(#"C:\destination");
if (destinationDirectory.Exists == false)
{
sourceDirectory.Copy(destinationDirectory, recursively: true);
}

Categories

Resources