This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I perform full recursive directory & file scan?
I can't find any informations, how to create a full directory listing in C#, including all files inside and all its subfolders's files, i.e:
c:\a.jpg
c:\b.php
c:\c\d.exe
c:\e\f.png
c:\g\h.mpg
You can use DirectoryInfo.GetFiles("C:\*.*", SearchOption.AllDirectories);
This will return an array of FileInfo objects, which include a Name and FullName property for the filename.
That being said, I would not do this on "C:\", as you'll return a huge array, but this technique will work correctly on an appropriate folder.
If you're using .NET 4, I'd recommend using EnumerateFiles instead, which will return an IEnumerable<T> instead of an array.
Note that the above code will most likely fail, however, as it requires full permissions to search the file system. A SecurityException will be raised if you can't access specific parts of the file system you're trying to search.
Also - if you're only interested in the file names and not the full FileInfo information, you can use Directory.EnumerateFiles instead, which returns an IEnumerable<string> with all of the relevant filenames.
There is an MSDN Article with code examples to do just this.
This is the money:
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);
}
}
Related
Hi I am trying to search for all files and folders that start with a given sequence of characters in a specific path. (The path is given by the user and so is the sequence).
To accomplish this I have been using the Directory.GetFiles and Directory.GetDirectories methods.
However when I search with no search option defined, it doesn't return all the files / folders that could've been found. So I added the SearchOption.AllDirectiories argument but when it's present, the function doesn't return anything.
This is my code:
try
{
// Search for directories
foreach (string d in Directory.GetDirectories(path, $"{param}*", SearchOption.AllDirectories))
{
Console.WriteLine(d);
found_directories.Add(d);
}
Console.WriteLine("");
// Search for files
foreach (string f in Directory.GetFiles(path, $"{param}*", SearchOption.AllDirectories))
{
Console.WriteLine(f);
found_files.Add(f);
}
}
catch (UnauthorizedAccessException)
{
// Some directories cannot be accessed and hence cause the program to crash
// So it's neccesary to catch the error
}
break;
I have already looked at these posts (which didn't help me):
Directory.GetFiles Not returning a file
Directory.GetFiles(path, ".txt", SearchOption.AllDirectories); doesn't deliver a file
Directory.GetFiles - SearchOption.AllDirectories Does not give files in subfolders (vb)
So after doing a little bit of research I found the issue.
Directory.GetFiles() / Directory.GetDirectories() are inherently flawed. When any exception occurs the function does not continue searching for files / folders. It's because there's no error handling inside these functions. Trying to write the try/catch yourself is non beneficial, since even when you catch an exception, the function will finish without returning anything.
Is there a solution?
No, but there's a workaround.
The workaround
Use this github repo instead: https://github.com/astrohart/FileSystemEnumerable/
It is an improved version of the function, it does all the error handling so you don't need to worry about anything, I tested it myself and it works for me.
The github repo is realated to this stackoverflow question.
For anyone that would maybe have the same problem in the future, I recommend you check out this link.
I hope that by answering my own question, I helped someone in the future.
Cheers :)!
This question already has an answer here:
UnauthorizedAccessException while getting files
(1 answer)
Closed 9 years ago.
I want my application to search through the whole computer for a specific file, and open it.
I tried:
var files = new List<string>();
foreach (DriveInfo d in DriveInfo.GetDrives().Where(x => x.IsReady == true))
{
files.AddRange(Directory.GetFiles(d.RootDirectory.FullName, "Kalimba.mp3", SearchOption.AllDirectories));
}
Got error: No access C:\$Recycle.Bin\S-1-5-18.
Well your DirectoryInfo.GetFiles method throws an UnauthorizedAccessException exception cause you don't have access to this hidden directory.
Correction: catch the exception.
UPDATE: as the comments say, you're getting all your files in a single GetFiles call, so catching the exception won't help. Slightly modify your code to manually get the list of directories, so you can catch and handle the exception for the specific directory you have not rights on.
See How to recursively list all the files in a directory in C#? for a complete example.
I have a root node A which contains B which contains C which contains D which contains an XML file abc.xml
So in D:\ drive ,I have the following structure of directories A>>B>>C>>D.
This path is dynamic. What is the best practice to read the file abc.xml in C# by iterating through the physical folders?
You could implement a recursive search algorithm that goes through all the folders and descends into the sub folders.
Pseudo Code:
public void GetXMLFilesRecursive(string currentFolder, List<string> results)
{
// Enumerate all directories of currentFolder
string[] folders = Directory.GetDirectories(currentFolder);
foreach (string folder in folders)
GetXMLFilesRecursive(folder, results));
// Enumerate all XML files in this folder only if it has no other sub-folders (is a leaf)
if (folders.Length == 0)
{
string[] xmlFiles = Directory.GetFiles(currentFolder, "*.xml");
results.AddRange(xmlFiles);
}
}
This method only returns XML files in the lowest folders of the hierarchy (i.e. folders that don't have sub folders). If you want all files you find along the way, comment out if (folders.Length == 0). On the other hand, you could then also use Directory.GetFiles with SearchOption.AllDirectories.
Why I wrote a recursive algorithm: The OP asked how to find all XML files in the leaf directories. You can not do that using Directory.GetFiles with SearchOption.AllDirectories, but you then need to implement the above.
You can use Directory.GetFiles(d, "*.xml",SearchOption.AllDirectories) to get all the xml files get what you are looking for.
You can search an entire tree for a file using Directory.GetFiles(path,searchPattern,SearchOption) or Directory.EnumerateFiles with SearchOption.AllDirectories, eg
var fullPaths=Directory.GetFiles(myPath,"abc.xml",SearchOption.AllDirectories)
You can also use the DirectoryInfo class to get full FileInfo instances instead of just the paths, with access to file properties and attributes:
var myDir=new DirectoryInfo(myPath);
var fileInfos=myDir.GetFiles("abc.xml",SearchOption.AllDirectories);
The difference between the GetFiles and EnumerateFiles methods is that the first returns an array with all the files found, blocking until it finds all of them. EnumerateFiles on the other hand returns results as it finds them, so you get to process the results much sooner.
What goes for GetFiles goes for the GetDirectories/EnumerateDirectories set of functions as well. The methods are available both from the Directory and DirectoryInfo class.
If you want to search for both directories and files, you can use GetFileSystemEntries/EnumerateFileSystemEntries to return both of them with a single call. The equivalent DirectoryInfo methods are GetFileSystemInfos/EnumerateFileSystemInfos
public List<string> getFiles(string path, string searchPattern, List<string> list)
{
try
{
foreach (string folder in Directory.GetDirectories(path))
getFiles(folder, searchPattern, list);
list.AddRange(Directory.GetFiles(path, searchPattern));
}
catch (UnauthorizedAccessException)
{
//Do not have access to the file.
}
return list;
}
Call like this:
//Get all xml files in the D drive:
List<string> files = getFiles(#"d:\", "*.xml", new List<string>());
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
After referring many blogs and articles, I have reached at the following code for searching for a string in all files inside a folder. It is working fine in my tests.
QUESTIONS
Is there a faster approach for this (using C#)?
Is there any scenario that will fail with this code?
Note: I tested with very small files. Also very few number of files.
CODE
static void Main()
{
string sourceFolder = #"C:\Test";
string searchWord = ".class1";
List<string> allFiles = new List<string>();
AddFileNamesToList(sourceFolder, allFiles);
foreach (string fileName in allFiles)
{
string contents = File.ReadAllText(fileName);
if (contents.Contains(searchWord))
{
Console.WriteLine(fileName);
}
}
Console.WriteLine(" ");
System.Console.ReadKey();
}
public static void AddFileNamesToList(string sourceDir, List<string> allFiles)
{
string[] fileEntries = Directory.GetFiles(sourceDir);
foreach (string fileName in fileEntries)
{
allFiles.Add(fileName);
}
//Recursion
string[] subdirectoryEntries = Directory.GetDirectories(sourceDir);
foreach (string item in subdirectoryEntries)
{
// Avoid "reparse points"
if ((File.GetAttributes(item) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)
{
AddFileNamesToList(item, allFiles);
}
}
}
REFERENCE
Using StreamReader to check if a file contains a string
Splitting a String with two criteria
C# detect folder junctions in a path
Detect Symbolic Links, Junction Points, Mount Points and Hard Links
FolderBrowserDialog SelectedPath with reparse points
C# - High Quality Byte Array Conversion of Images
Instead of File.ReadAllText() better use
File.ReadLines(#"C:\file.txt");
It returns IEnumerable (yielded) so you will not have to read the whole file if your string is found before the last line of the text file is reached
I wrote somthing very similar, a couple of changes I would recommend.
Use Directory.EnumerateDirectories instead of GetDirectories, it returns immediately with a IEnumerable so you don't need to wait for it to finish reading all of the directories before processing.
Use ReadLines instead of ReadAllText, this will only load one line in at a time in memory, this will be a big deal if you hit a large file.
If you are using a new enough version of .NET use Parallel.ForEach, this will allow you to search multiple files at once.
You may not be able to open the file, you need to check for read permissions or add to the manifest that your program requires administrative privileges (you should still check though)
I was creating a binary search tool, here is some snippets of what I wrote to give you a hand
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Parallel.ForEach(Directory.EnumerateFiles(_folder, _filter, SearchOption.AllDirectories), Search);
}
//_array contains the binary pattern I am searching for.
private void Search(string filePath)
{
if (Contains(filePath, _array))
{
//filePath points at a match.
}
}
private static bool Contains(string path, byte[] search)
{
//I am doing ReadAllBytes due to the fact that I am doing a binary search not a text search
// There are no "Lines" to seperate out on.
var file = File.ReadAllBytes(path);
var result = Parallel.For(0, file.Length - search.Length, (i, loopState) =>
{
if (file[i] == search[0])
{
byte[] localCache = new byte[search.Length];
Array.Copy(file, i, localCache, 0, search.Length);
if (Enumerable.SequenceEqual(localCache, search))
loopState.Stop();
}
});
return result.IsCompleted == false;
}
This uses two nested parallel loops. This design is terribly inefficient, and could be greatly improved by using the Booyer-Moore search algorithm but I could not find a binary implementation and I did not have the time when I wrote it originally to implement it myself.
the main problem here is that you are searching all the files in real time for every search. there is also the possibility of file access conflicts if 2+ users are searching at the same time.
to dramtically improve performance I would index the files ahead of time, and as they are edited/saved. store the indexed using something like lucene.net and then query the index (again using luence.net) and return the file names to the user. so the user never queries the files directly.
if you follow the links in this SO Post you may have a head start on implementing the indexing. I didn't follow the links, but it's worth a look.
Just a heads up, this will be an intense shift from your current approach and will require
a service to monitor/index the files
the UI project
I think your code will fail with an exception if you lack permission to open a file.
Compare it with the code here: http://bgrep.codeplex.com/releases/view/36186
That latter code supports
regular expression search and
filters for file extensions
-- things you should probably consider.
Instead of Contains better use algorithm Boyer-Moore search.
Fail scenario: file have not read permission.
I want to make an exact copy of some files, directories and subdirectories that are on my USB drive I:/ and want them to be in C:/backup (for example)
My USB drive has the following structure:
(just to know, this is an example, my drive has more files, directories and subdirectories)
courses/data_structures/db.sql
games/pc/pc-game.exe
exams/exam01.doc
Well, I am not sure how to start with this but my first idea is to get all the files doing this:
string[] files = Directory.GetFiles("I:");
The next step could be to make a loop and use File.Copy specifying the destination path:
string destinationPath = #"C:/backup";
foreach (string file in files)
{
File.Copy(file, destinationPath + "\\" + Path.GetFileName(file), true);
}
At this point everything works good but not as I wanted cause this doesn't replicate the folder structure. Also some errors happen like the following...
The first one happens because my PC configuration shows hidden files for every folder and my USB has an AUTORUN.INF hidden file that is not hidden anymore and the loop tries to copy it and in the process generates this exception:
Access to the path 'AUTORUN.INF' is denied.
The second one happens when some paths are too long and this generates the following exception:
The specified path, file name, or both are too long. The fully
qualified file name must be less than 260 characters, and the
directory name must be less than 248 characters.
So, I am not sure how to achieve this and validate each posible case of error. I would like to know if there is another way to do this and how (maybe some library) or something more simple like an implemented method with the following structure:
File.CopyDrive(driveLetter, destinationFolder)
(VB.NET answers will be accepted too).
Thanks in advance.
public static void Copy(string src, string dest)
{
// copy all files
foreach (string file in Directory.GetFiles(src))
{
try
{
File.Copy(file, Path.Combine(dest, Path.GetFileName(file)));
}
catch (PathTooLongException)
{
}
// catch any other exception that you want.
// List of possible exceptions here: http://msdn.microsoft.com/en-us/library/c6cfw35a.aspx
}
// go recursive on directories
foreach (string dir in Directory.GetDirectories(src))
{
// First create directory...
// Instead of new DirectoryInfo(dir).Name, you can use any other way to get the dir name,
// but not Path.GetDirectoryName, since it returns full dir name.
string destSubDir = Path.Combine(dest, new DirectoryInfo(dir).Name);
Directory.CreateDirectory(destSubDir);
// and then go recursive
Copy(dir, destSubDir);
}
}
And then you can call it:
Copy(#"I:\", #"C:\Backup");
Didn't have time to test it, but i hope you get the idea...
edit: in the code above, there are no checks like Directory.Exists and such, you might add those if the directory structure of some kind exists at destination path. And if you're trying to create some kind of simple sync app, then it gets a bit harder, as you need to delete or take other action on files/folders that don't exist anymore.
This generally starts with a recursive descent parser. Here is a good example: http://msdn.microsoft.com/en-us/library/bb762914.aspx
You might want to look into the overloaded CopyDirectory Class
CopyDirectory(String, String, UIOption, UICancelOption)
It will recurse through all of the subdirectories.
If you want a standalone application, I have written an application that copies from one selected directory to another, overwriting newer files and adding subdirectories as needed.
Just email me.