How to get files from a specific sub-directories using c#? - c#

I'm trying to get all *.html files which are inside sub-directories named abcd to an array.
The path given can contain multiple *.html files in multiple sub-directories and even in the root directory(i.e. immediately inside the user given path) but I only want those *.html files which are inside the specificly named sub-directories(abcd) using LINQ.
This is what I tried
string workingPath = #"D:\Testing";
string[] myFiles = workingPath.Select(dirs => Directory.GetDirectories(workingPath)
.Select(folders => (from item in Directory.GetDirectories(folders, "abcd", SearchOption.AllDirectories)
.Select(item => Directory.GetFiles(item, "*.html"))
)));
I'm getting an error
A query body must end with a select clause or a group clause (CS0742)
. How do I fix this?

Your code does not look like it will compile. To start with workingPath.Select will return a collection of chars and you are trying to iterate over that again , which does not make sense considering your requirements.
You need something like this
var files = new List<string>();
if (Directory.Exists(workingPath))
{
foreach (var f in Directory.GetDirectories(workingPath, "abcd",
SearchOption.AllDirectories))
{
files.AddRange(Directory.GetFiles(f, "*.html"));
}
}
You can also do a one liner using LINQ
var files2 = Directory.GetDirectories(workingPath, "abcd", SearchOption.AllDirectories)
.SelectMany(d => Directory.GetFiles(d, "*.html")).ToArray();

Related

Show list from last file to first save

I want to reverse the result displayed in a Combobox.
The last saved file would appear first, currently it is the opposite. it appears with this code:
string[] files = Directory.GetFiles(#"C:\Test\",*.TXT");
foreach (string file in files)
{
comboBox1.Items.Add(Path.GetFileNameWithoutExtension(file));
}
According to my research, the solution would be:
.OrderByDescending(p => p.CreationTime).ToArray();
added somewhere. But I don't know. Every attempt I've made has been unsuccessful.
Currently:
101-00.06.52.TXT
101-00.06.54.TXT
101-00.06.56.TXT
Desired outcome:
101-00.06.56.TXT
101-00.06.54.TXT
101-00.06.52.TXT
Does anyone know?
Instead of static method Directory.GetFiles() method, use GetFiles() method from DirectoryInfo class. Apply OrderByDescending() on it.
Directory.GetFiles():
Returns the names of files that meet specified
criteria
Vs
DirectoryInfo.GetFiles():
Returns a file list from the current directory.
Like,
DirectoryInfo di = new DirectoryInfo(#"C:\Test\"); //Get the Directory information
var allTxtFiles = di.GetFiles("*.txt") //Get all files based on search pattern
.OrderByDescending(p => p.CreationTime) //Sort by CreationTime
.Select(x => x.Name); //Select only name from FileInfo object
foreach (string file in allTxtFiles)
{
comboBox1.Items.Add(Path.GetFileNameWithoutExtension(file));
}
I don't know the reason why you problem. But if you want to receive correct result is simple. First try this:
string[] files = Directory.GetFiles(#"C:\Test\",*.TXT");
comboBox1.ItemsSource = files;
if the result is not correct. Use this:
string[] files = Directory.GetFiles(#"C:\Test\",*.TXT");
files = files.Reverse();
comboBox1.ItemsSource = files;

LINQ IN where query

I want to write foreach loop to get all files with specified extention from external txt file. For example I have in file variable:
extensions = "jpg,tif,bmp,png" or
extensions "jpg,tif" and I want to only get this files.
So far I have something like this but I don`t know how to go on.
extensions = Extensions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string sourceFile in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(extensions.)))
{
}
I don`t know how to get to every element in 'extensions' array. How can I solved that?
You can use Enumerable.Contains and System.IO.Path.GetExtension:
string[] extensions = {".jpg",".tif",".bmp",".png" };
var files = Directory.EnumerateFiles(SourcePath, "*.*", SearchOption.AllDirectories)
.Where(s => extensions.Contains(Path.GetExtension(s), StringComparer.InvariantCultureIgnoreCase));

LINQ nested list comprehension to get files from several folders

I am trying to get .mp3 files from multiple folders.
I can already do it for one folder through this query :
this.MusicList.ItemsSource =
from string fileName in Directory.GetFiles(#"C:\Users\Public\Music\Sample Music")
where System.IO.Path.GetExtension(fileName) == ".mp3"
select new FileInfo(fileName);
Is there any other way to do it for a list of directories ?
Here is what I have tried so far (returns no results):
var paths = new Dictionary<string, string> {
{"default_music", #"C:\Users\Public\Music\Sample Music"},
{"alternative_folder", #"C:\tmp"}
};
this.MusicList.ItemsSource =
from string fileName in (from string directoryName in paths.Values select Directory.GetFiles(directoryName))
where System.IO.Path.GetExtension(fileName) == ".mp3"
select new FileInfo(fileName);
from string directoryName in paths.Values select Directory.GetFiles(directoryName); returns a {System.Linq.Enumerable.WhereSelectEnumerableIterator<string,string[]>} with my paths in its source field and its Result View contains of my .mp3 files.
Thank you
Try the following
this.MusicList.ItemsSource =
from path in paths
from fileName in Directory.GetFiles(path)
where System.IO.Path.GetExtension(fileName) == ".mp3"
select new FileInfo(fileName);
Strict method call version
this.MusicList.ItemSource = paths
.SelectMany(path => Directory.GetFiles(path))
.Where(fileName => System.IO.Path.GetExtension(fileName) == ".mp3")
.Select(fileName => new FileInfo(fileName));
You can use DirectoryInfo.EnumerateFiles method which accepts search pattern. Thus you don't need to get all files and filter them via calls to Path.GetExtension
var paths = new Dictionary<string, string> {
{"default_music", #"C:\Users\Public\Music\Sample Music"},
{"alternative_folder", #"C:\tmp"}
};
MusicList.ItemsSource = paths.Values.Select(p => new DirectoryInfo(p))
.SelectMany(d => d.EnumerateFiles("*.mp3"));
Also DirectoryInfo.EnumerateFiles returns FileInfo instances, which is also what you want.
Try this
Directory.EnumerateFiles(#"C:\Users\Public\Music\Sample Music", "*.mp3", SearchOption.AllDirectories)
to return an enumerable list of .mp3's, which you can further filter or enumerate etc. This is more efficient than GetFiles() for large numbers of files and/or directories.
http://msdn.microsoft.com/en-us/library/dd383571.aspx
Alternate to the esteemable JaredPar that tracks if it's a File/Directory:
var basePath = #"c:\temp";
var query =
from entry in Directory.EnumerateFileSystemEntries(basePath, "*.*", SearchOption.AllDirectories)
let isDirectory = Directory.Exists(entry)
let isFile = File.Exists(entry)
select new { isDirectory, isFile, entry};
query.Dump();
EDIT: Doh - misread question, missed the "from a set of directories" part; my shame is immeasurable. :)

Find in Files C#

I have a Folder which has multiple sub folders. Each sub folder has many .dot and .txt files in them.
Is there a simple solution in C# .NET that will iterate through each file and check the contents of that file for a key phrase or keyword?
Document Name Keyword1 Keyword2 Keyword3 ...
test.dot Y N Y
To summarise:
Select a folder
Enter a list of keywords to search for
The program will then search through each file and at the end output something like above, I am not to worried about creating the datatable to show the datagrid as I can do this. I just need to perform the find in files function similar to Notepad++'s find in files option
Thanks in advance
What you want is recursively iterate files in a directory (and maybe it's subdirectories).
So your steps would be to loop eeach file in the specified directory with Getfiles() from .NET. then if you encounter a directory loop it again.
This can be easily done with this code sample:
public static IEnumerable<string> GetFiles(string path)
{
foreach (string s in Directory.GetFiles(path, "*.extension_here"))
{
yield return s;
}
foreach (string s in Directory.GetDirectories(path))
{
foreach (string s1 in GetFiles(s))
{
yield return s1;
}
}
}
A more indepth look on iterating throug files in directories in .NET is located here:
http://blogs.msdn.com/b/brada/archive/2004/03/04/84069.aspx
Then you use the IndexOf method from String to check if your keywords are in the file (I discourage the use of ReadAllText, if your file is 5 MB big, your string will be too. Line-by-line will be less memory-hungry)
You can use Directory.EnumerateFiles with a searchpattern and the recursive hint(SearchOption.AllDirectories). The rest is easy with LINQ:
var keyWords = new []{"Y","N","Y"};
var allDotFiles = Directory.EnumerateFiles(folder, "*.dot", SearchOption.AllDirectories);
var allTxtFiles = Directory.EnumerateFiles(folder, "*.txt", SearchOption.AllDirectories);
var allFiles = allDotFiles.Concat(allTxtFiles);
var allMatches = from fn in allFiles
from line in File.ReadLines(fn)
from kw in keyWords
where line.Contains(kw)
select new {
File = fn,
Line = line,
Keyword = kw
};
foreach (var matchInfo in allMatches)
Console.WriteLine("File => {0} Line => {1} Keyword => {2}"
, matchInfo.File, matchInfo.Line, matchInfo.Keyword);
Note that you need to add using System.Linq;
Is there a way just to get the line number?
If you just want the line numbers you can use this query:
var matches = allFiles.Select(fn => new
{
File = fn,
LineIndices = String.Join(",",
File.ReadLines(fn)
.Select((l,i) => new {Line=l, Index =i})
.Where(x => keyWords.Any(w => x.Line.Contains(w)))
.Select(x => x.Index)),
})
.Where(x => x.LineIndices.Any());
foreach (var match in matches)
Console.WriteLine("File => {0} Linenumber => {1}"
, match.File, match.LineIndices);
It's a little bit more difficult since LINQ's query syntax doesn't allow to pass the index.
The first step: locate all files. It is easily done with System.IO.Directory.GetFiles() + System.IO.File.ReadAllText(), as others have mentioned.
The second step: find keywords in a file. This is simple if you have one keyword and it can be done with IndexOf() method, but iterating a file multiple times (especially if it is big) is a waste.
To quickly find multiple keywords in a text I think you should use the Aho-Corasick automaton (algorithm). See the C# implementation at CodeProject: http://www.codeproject.com/Articles/12383/Aho-Corasick-string-matching-in-C
Here's a way using Tim's original answer to get the line number:
var keyWords = new[] { "Keyword1", "Keyword2", "Keyword3" };
var allDotFiles = Directory.EnumerateFiles(folder, "*.dot", SearchOption.AllDirectories);
var allTxtFiles = Directory.EnumerateFiles(folder, "*.txt", SearchOption.AllDirectories);
var allFiles = allDotFiles.Concat(allTxtFiles);
var allMatches = from fn in allFiles
from line in File.ReadLines(fn).Select((item, index) => new { LineNumber = index, Line = item})
from kw in keyWords
where line.Line.Contains(kw)
select new
{
File = fn,
Line = line.Line,
LineNumber = line.LineNumber,
Keyword = kw
};
foreach (var matchInfo in allMatches)
Console.WriteLine("File => {0} Line => {1} Keyword => {2} Line Number => {3}"
, matchInfo.File, matchInfo.Line, matchInfo.Keyword, matchInfo.LineNumber);

c# Directory.GetFiles file structure from app root

I have the following piece of code:
string root = Path.GetDirectoryName(Application.ExecutablePath);
List<string> FullFileList = Directory.GetFiles(root, "*.*",
SearchOption.AllDirectories).Where(name =>
{
return !(name.EndsWith("dmp") || name.EndsWith("jpg"));
}).ToList();
Now this works very well, however the file names with it are quire long.
is there a way i can take out the path till root? but still show all the subfolders?
Root = C:\Users\\Desktop\Test\
But the code would return the whole path from C:
while I'd prefer if I could take out the root bit straight away. but still keep the file structure after it.
eg
C:\Users\\Desktop\Test\hi\hello\files.txt
would return
\hi\hello\files.txt
I know i can just iterate over the file list generated and remove it all one by one, I'm wondering if I can just filter it out stright.
Using the power of LINQ:
string root = Path.GetDirectoryName(Application.ExecutablePath);
List<string> FullFileList = Directory.GetFiles(root, "*.*", SearchOption.AllDirectories)
.Where(name =>
{
return !(name.EndsWith("dmp") || name.EndsWith("jpg"));
})
.Select(file => file.Replace(root, "")
.ToList();

Categories

Resources