I need help adding current logged %USER% to the path, this is my code so far:
DirectoryInfo dir = new DirectoryInfo(#"%USERPROFILE%\Local Settings\TEST");
foreach (FileInfo files in dir.GetFiles())
{
files.Delete();
}
foreach (DirectoryInfo dirs in dir.GetDirectories())
{
dirs.Delete(true);
}
how can I make him read %USERPROFILE% as current user?
I would love an example to figure things out, btw I want to use it to delete C:\Document and settings\%USERPFORILE%\Local Settings\Temp
Just wanted to add that while Environment.SpecialFolder.UserProfile is a good answer to your specific question, there's also another option that works for all environment variables, not just those that have a SpecialFolder accessor: Environment.ExpandEnvironmentVariables.
It will take a string, like your #"%USERPROFILE%\Local Settings\TEST", and return a new string with all %% environment variables expanded.
How about this:
void Main()
{
string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string subFolder = #"Local Settings\TEST";
string path = Path.Combine(userProfile, subFolder);
DirectoryInfo di = new DirectoryInfo(path);
if (di.Exists)
{
Console.WriteLine("Deleting " + di);
di.Delete(true);//recursive
}
else
{
Console.WriteLine("Directory " + di + " was not found");
}
}
I think that this is what you actually want:
String appData =
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
Use that instead of the Code Local Setting folder if you want to store data or do something.
(as my comment said, the Local setting folder is protected and that way you won't be able to open it)
The best way is to use Environment.ExpandEnvironmentVariables
void Main() {
string path = Environment.ExpandEnvironmentVariables(#"%USERPROFILE%\Local Settings\TEST");
DirectoryInfo dir = new DirectoryInfo(path);
foreach (FileInfo files in dir.GetFiles())
{
files.Delete();
}
foreach (DirectoryInfo dirs in dir.GetDirectories())
{
dirs.Delete(true);
}
}
https://msdn.microsoft.com/en-us/library/system.environment.expandenvironmentvariables.aspx
Related
I am currently writing a program in C# that will copy all user profile files to an external device (in this case, my home server).
When my code iterates through my files and folders, it throws an UnauthorizedAccessException.
I have Googled this and searched StackOverflow, but I am unable to find a clear solution that doesn't involve terminating my process. The idea is that it should copy the files and folders that have read permissions.
I had this when I first started, but I easily fixed it by limiting what directories I would backup (though I would prefer a full backup).
Here is my code:
FileInfo f = new FileInfo(_configuration.Destination);
if (!f.Directory.Exists)
{
f.Directory.Create();
}
string[] backupDirectories = new string[]
{
"Desktop",
"Documents",
"Downloads",
"Favorites",
"Links",
"Pictures",
"Saved Games",
"Searches",
"Videos",
".git",
".android",
".IdealC15",
".nuget",
".oracle_jre_usage",
".vs",
"Contacts"
};
foreach (string dirPath in backupDirectories)
{
DirectoryInfo dirInfo = new DirectoryInfo(_path + "\\" + dirPath);
if (dirInfo.Exists)
{
foreach (string dirP in Directory.GetDirectories(dirInfo.FullName, "*", SearchOption.AllDirectories))
{
DirectoryInfo dirI = new DirectoryInfo(dirP);
if (dirI.Exists)
{
string dir = dirP.Replace(_path, _configuration.Destination);
try
{
Directory.CreateDirectory(dir);
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Create Directory: " + dir + Environment.NewLine);
});
} catch (Exception e)
{
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Could NOT Create Directory: " + dir + Environment.NewLine);
});
continue;
}
foreach (FileInfo theFile in dirInfo.GetFiles("*", SearchOption.AllDirectories))
{
string newPath = theFile.FullName;
string file = newPath.Replace(_path, _configuration.Destination);
try
{
File.Copy(newPath, file, true);
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Create File: " + file + Environment.NewLine);
});
} catch (Exception ex)
{
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Could NOT Create File: " + file + Environment.NewLine);
});
}
}
}
}
}
}
I apologise if the code is messy, but I will describe sort of what it is doing. The first bit checks if the backup folder exists on the external drive.
The second part says what folders I need to backup (if you're able to fix this and make it backup all directories with permissions, please help me in doing so).
The first loop starts the iteration for each of the backupDirectories. The second loop starts the iteration for each of the directories in the backup directory. The third loop starts the iteration for each of the folders in the backup directory.
The exception is thrown at Directory.GetDirectories(dirInfo.FullName, "*", SearchOption.AllDirectories), and it is trying to access C:\Users\MyName\Documents\My Music. Attempting to access it in explorer does give me a permissions error, though it isn't listed in explorer when I try going to "Documents" (I am in Windows 10 Pro).
As I recommended, since the Operating System authority is higher than the application, it is likely that you cannot do more than what the Operating System would allow you to do (that is to access or not to access certain folder).
Thus, folders' accessibility is best solved in the Operating System level.
But you could still do two things in the program level to minimize the damage when you search for the items.
To use Directory.AccessControl to know the access level of a directory before you do any query on it. This is not so easy, and there are elaborated answers about this here and also here.
To minimize the damage made by unauthorized access issues by using SearchOption.TopDirectoryOnly instead of SearchOption.AllDirectories, combined with recursive search for all the accessible directories. This is how you can code it
public static List<string> GetAllAccessibleDirectories(string path, string searchPattern) {
List<string> dirPathList = new List<string>();
try {
List<string> childDirPathList = Directory.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly).ToList(); //use TopDirectoryOnly
if (childDirPathList == null || childDirPathList.Count <= 0) //this directory has no child
return null;
foreach (string childDirPath in childDirPathList) { //foreach child directory, do recursive search
dirPathList.Add(childDirPath); //add the path
List<string> grandChildDirPath = GetAllAccessibleDirectories(childDirPath, searchPattern);
if (grandChildDirPath != null && grandChildDirPath.Count > 0) //this child directory has children and nothing has gone wrong
dirPathList.AddRange(grandChildDirPath.ToArray()); //add the grandchildren to the list
}
return dirPathList; //return the whole list found at this level
} catch {
return null; //something has gone wrong, return null
}
}
The function above minimize the damage caused by the unauthorized access only to the sub-directories which have the issue. All other accessible directories can be returned.
I have this test path:
private static string dCrawler = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "TestLetters";
Is there a way to say:
foreach (item in dCrawler)
{
if (item.isFile)
{
// check file info date modified code
} else
{
foreach (fileinfo file in ...
}
}
so far I have only found ways to check a file in a directory. Is the only way to do it by having two separate loops one for files and one for folders?
You can use Directory.GetFiles(); that returns a string[] and use the string value to create your FileInfo. Like this
foreach (string n in Directory.GetFiles(dCrawler))
{
FileInfo b = new FileInfo(n);
}
To get directories, you can similarly use Directory.GetDirectories();
foreach (string n in Directory.GetDirectories(dCrawler))
{
DirectoryInfo b = new DirectoryInfo(n);
}
I am using SharpDevelop to write a C# program (not console).
I want to delete files within a specified directory, but be able to EXCLUDE files beginning, ending, or containing certain words.
TO completely delete ALL files in a folder I am using this :
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();
}
}
I use it like
ClearFolder("NameOfFolderIWantToEmpty");
Is there a way to modify this so that I can delete all files and direcotries EXCEPT those files and directories containing specific words?
Something like :
CleanFolder(FolderToEmpty,ExcludeAllFileAndDirectoriesContaingThisPhrase);
so that if I did
CleanFolder("MyTestFolder","_blink");
It would NOT delete files and directories with names like
_blinkOne (file)
Test_blineGreen (file)
Test_blink5 (directory)
_blinkTwo (file within the Text_blink5 directory)
Folder_blink (empty directory)
but WOULD delete files and directories like
test (file)
test2 (directory)
test3_file (file within test2 directory)
test4 (empty directory)
I suspect I might have to iterate through each file and directory, checking them one at a time for the matching filter and deleting it if it does not match, but I am not sure how to do that.
Something with FileInfo() and DirectoryInfo() perhaps?
Can somebody help by providing a working example?
(modified version of the above is preferred, but if a new method is required, as long as it doesn't require an outside dll, is OK.
Just test to see if the FileInfo.Name property (string) StartsWith or EndsWith a specified string.
foreach (FileInfo fInfo in di.GetFiles())
{
if (!fInfo.Name.StartsWith("AAA") ||
!fInfo.Name.EndsWith("BBB"))
{
fInfo.Delete();
}
}
Or if you are looking for a word anywhere in the filename, use the Contains method:
foreach (FileInfo fInfo in di.GetFiles())
{
if (!fInfo.Name.Contains("CCC"))
{
fInfo.Delete();
}
}
Use the Directory.GetFiles(string, string) method to get a list of files that match your pattern, and use Enumerable.Except(IEnumerable<T>) to get the files you actually want to delete.
string pattern = "*.*";
var matches = Directory.GetFiles(folderName, pattern);
foreach(string file in Directory.GetFiles(folderName).Except(matches))
File.Delete(file);
There's no need to use DirectoryInfo here, since you appear to be concerned only with manipulating the files in the directory.
if(!fi.Name.Contains("_blink"))
fi.Delete();
I think I have a solution that will work for me.
Posting the full code here so that others may use it, tweak it, and/or examine it for possible flaws.
This is my first time using StackOverFlow, and knowing that I have this resource available to search and the ability to ask questions and people can actually help, is a great comfort to me as a person who is new to all of this stuff.
Thanks a ton everybody!
// Search directory recursively and delete ALL sub-directories and files
// with names that do NOT contain the given search pattern
private void clearFolderWithFilter(string folderName, string filesToExclude)
{
DirectoryInfo dir = new DirectoryInfo(folderName);
foreach(FileInfo fi in dir.GetFiles())
{
if(!fi.Name.Contains(filesToExclude))
{
// System.Diagnostics.Debug.WriteLine("DELETING file " + fi + " because it does NOT contain '" + filesToExclude + "' ");
fi.Delete();
} else {
// System.Diagnostics.Debug.WriteLine("SAVING file " + fi + " because it contains '" + filesToExclude + "' ");
}
}
foreach (DirectoryInfo di in dir.GetDirectories())
{
if(!di.Name.Contains(filesToExclude))
{
// System.Diagnostics.Debug.WriteLine("DELETING directory " + di + " because it does NOT contain '" + filesToExclude + "' ");
clearFolderWithFilter(di.FullName, filesToExclude);
di.Delete();
} else {
// System.Diagnostics.Debug.WriteLine("SAVING directory " + di + " because it contains '" + filesToExclude + "' ");
}
}
}
Usage :
clearFolderWithFilter(#"C:\Path\MyFolder","DoNotDelete_");
I am using this code:
DirectoryInfo dir = new DirectoryInfo("D:\\");
foreach (FileInfo file in dir.GetFiles("*.*",SearchOption.AllDirectories))
{
MessageBox.Show(file.FullName);
}
I get this error:
UnauthorizedAccessException was unhandled
Access to the path 'D:\System Volume Information\' is denied.
How might I solve this?
There is no way in .NET to override privileges of the user you are running this code as.
There's only 1 option really. Make sure only admin runs this code or you run it under admin account.
It is advisable that you either put "try catch" block and handle this exception or
before you run the code you check that the user is an administrator:
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal currentPrincipal = new WindowsPrincipal(currentIdentity);
if (currentPrincipal.IsInRole(WindowsBuiltInRole.Administrator))
{
DirectoryInfo dir = new DirectoryInfo("D:\\");
foreach (FileInfo file in dir.GetFiles("*.*",SearchOption.AllDirectories))
{
MessageBox.Show(file.FullName);
}
}
try calling this method putting one more try catch block before calling - this will mean top folder lacks required authorisation:
static void RecursiveGetFiles(string path)
{
DirectoryInfo dir = new DirectoryInfo(path);
try
{
foreach (FileInfo file in dir.GetFiles())
{
MessageBox.Show(file.FullName);
}
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("Access denied to folder: " + path);
}
foreach (DirectoryInfo lowerDir in dir.GetDirectories())
{
try
{
RecursiveGetFiles(lowerDir.FullName);
}
catch (UnauthorizedAccessException)
{
MessageBox.Show("Access denied to folder: " + path);
}
}
}
}
You can manually search the file tree ignoring system directories.
// Create a stack of the directories to be processed.
Stack<DirectoryInfo> dirstack = new Stack<DirectoryInfo>();
// Add your initial directory to the stack.
dirstack.Push(new DirectoryInfo(#"D:\");
// While there are directories on the stack to be processed...
while (dirstack.Count > 0)
{
// Set the current directory and remove it from the stack.
DirectoryInfo current = dirstack.Pop();
// Get all the directories in the current directory.
foreach (DirectoryInfo d in current.GetDirectories())
{
// Only add a directory to the stack if it is not a system directory.
if ((d.Attributes & FileAttributes.System) != FileAttributes.System)
{
dirstack.Push(d);
}
}
// Get all the files in the current directory.
foreach (FileInfo f in current.GetFiles())
{
// Do whatever you want with the files here.
}
}
Listing all files in a drive other than my system drive throws an UnauthorizedAccessException.
How can I solve this problem?
Is there a way to grant my application the access it needs?
My code:
Directory.GetFiles("S:\\", ...)
Here's a class that will work:
public static class FileDirectorySearcher
{
public static IEnumerable<string> Search(string searchPath, string searchPattern)
{
IEnumerable<string> files = GetFileSystemEntries(searchPath, searchPattern);
foreach (string file in files)
{
yield return file;
}
IEnumerable<string> directories = GetDirectories(searchPath);
foreach (string directory in directories)
{
files = Search(directory, searchPattern);
foreach (string file in files)
{
yield return file;
}
}
}
private static IEnumerable<string> GetDirectories(string directory)
{
IEnumerable<string> subDirectories = null;
try
{
subDirectories = Directory.EnumerateDirectories(directory, "*.*", SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
}
if (subDirectories != null)
{
foreach (string subDirectory in subDirectories)
{
yield return subDirectory;
}
}
}
private static IEnumerable<string> GetFileSystemEntries(string directory, string searchPattern)
{
IEnumerable<string> files = null;
try
{
files = Directory.EnumerateFileSystemEntries(directory, searchPattern, SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
}
if (files != null)
{
foreach (string file in files)
{
yield return file;
}
}
}
}
You can the use it like this:
IEnumerable<string> filesOrDirectories = FileDirectorySearcher.Search(#"C:\", "*.txt");
foreach (string fileOrDirectory in filesOrDirectories)
{
// Do something here.
}
It's recursive, but the use of yield gives it a low memory footprint (under 10KB in my testing). If you want only files that match the pattern and not directories as well just replace EnumerateFileSystemEntries with EnumerateFiles.
Are you allowed to access the drive? Can the program access the drive when it's not run from Visual Studio? Are restrictive permissions defined in the project's Security page ("Security Page, Project Designer")?
In .net core you can do something like this below. It can search for all subdirectories recursively with good performance and ignoring paths without access.
I also tried other methods found in
How to quickly check if folder is empty (.NET)? and
Is there a faster way than this to find all the files in a directory and all sub directories? and
https://www.codeproject.com/Articles/1383832/System-IO-Directory-Alternative-using-WinAPI
public static IEnumerable<string> ListFiles(string baseDir)
{
EnumerationOptions opt = new EnumerationOptions();
opt.RecurseSubdirectories = true;
opt.ReturnSpecialDirectories = false;
//opt.AttributesToSkip = FileAttributes.Hidden | FileAttributes.System;
opt.AttributesToSkip = 0;
opt.IgnoreInaccessible = true;
var tmp = Directory.EnumerateFileSystemEntries(baseDir, "*", opt);
return tmp;
}
I solved the problem. Not really but at least the source.
It was the SearchOption.AllDirectories option that caused the exception.
But when I just list the immediate files using Directories.GetFiles, it works.
This is good enough for me.
Any way to solve the recursive listing problem?