LINQ - Add static text to each result - c#

I have an array of files, but the problem is the root path isn't attached to the file, so using the data below, how would I go about appending the linq item to the static string?
string rootPath = "C:\\Users\\MyUserName";
List<string> files = new List<string>();
files.Add("\\My Documents\\File1.txt");
files.Add("\\My Documents\\File2.txt");
I essentially want a list that is Path.Combine(rootPath, x); I tried this but no luck:
var fileList = (from x in files
select Path.Combine(rootPath, x)).ToList();
But it doesn't append the rootPath, fileList is the same as the files list.
Any ideas?

Apparently Path.Combine will ignore the first parameter if the second parameter has a leading "\" (this blog entry has some more info).
This should work, it uses Path.Combine and the ? operator to account for leading slashes in the second parameter:
var fileList = (from f in files
select Path.Combine(rootPath,
f.StartsWith("\\") ? f.Substring(1) : f)).ToList();

the query works fine if you change
"\\My Documents\\File1.txt" to #"My Documents\\File1.txt" .
The reason is being described in the post mentioned by Donut.
Hence,
string rootPath = "C:\\Users\\MyUserName";
List<string> files = new List<string>();
files.Add(#"My Documents\\File1.txt");
files.Add(#"My Documents\\File2.txt");
var fileList = (from x in files select Path.Combine(rootPath, x)).ToList();
OR
var fileList = files.Select(i => Path.Combine(rootPath, i));
works fine.
If at all you donot want to change the existing source , then instead of Path.Combine use
string.Concat
e.g.
string rootPath = "C:\\Users\\MyUserName";
List<string> files = new List<string>();
files.Add("\\My Documents\\File1.txt");
files.Add("\\My Documents\\File2.txt");
var fileList = (from x in files select string.Concat(rootPath, x)).ToList();
OR
var fileList = files.Select(i => string.Concat(rootPath, i));
Hope this helps

Related

Adding File and Directory to Array

I have this method that searches all files and folders in "C:\Sharing".
string[] fileArray = Directory.GetFiles(#"C:\Sharing", "*.*", SearchOption.AllDirectories);
And foreach shows me full path of each file. Great. However, since these are in a directory called "Sharing", I want to check and add files that are like
C:\Sharing\Jerry2022\wedding.jpg (array: 'wedding.jpg', 'Jerry2022')
C:\Sharing\snapshot.jpg (array: 'snapshot.jpg')
C:\Sharing\Newsletter\cover-june.webp (array: 'cover-june.webp', 'Newsletter')
So as you can see, I want to add file and subdirectory name to a string array or List, doesnt matter. Excluding "Sharing".
How can I split the results? I know I can use Substring and LastIndexOf("\") + 1 and separate the ending '' but I'm not sure how to match up the filename with the subdir name too.
Any help is appreciated
You can use DirectoryInfo to get the information you want:
C#:
var directoryInfo = new DirectoryInfo(#"C:\Sharing");
if (directoryInfo.Exists)
{
foreach (var fileInfo in directoryInfo.GetFiles("*.*", SearchOption.AllDirectories))
{
var fileName = fileInfo.Name;
Console.WriteLine(fileName);
var directoryName = fileInfo.DirectoryName;
// you can use split to get the directory name array
Console.WriteLine(directoryName);
}
}
I found an other way, use Uri for this scenario:
C#:
string[] fileArray = Directory.GetFiles(#"C:\Sharing", "*.*", SearchOption.AllDirectories);
foreach (var s in fileArray)
{
var uri = new Uri(s);
var uriSegments = uri.Segments.ToArray();
}
You will see each part of the full path, but you may need to use .Trim('/') for each part. Then you can use string.Equals to get directories which you want.
You could split the results using Split
But of course you can also work with FileInfo instead

How to get last file that not contain specific string

I know how to get the last file, this the code:
string pattern = "Log*.xml";
string directory = set. Path;
var dirInfo = new DirectoryInfo(directory);
var file = (from f in dirInfo.GetFiles(pattern) orderby f.LastWriteTime descending select f).First();
My question is: How can I get the last file that not contain specific string? or in another words, how can I get the last file that not contain "This is temporally file" string?
Thank you!
from top of my head:
dirInfo.EnumerateFiles(pattern)
.OrderByDescending(f => f.LastWriteTime)
.Where(f => DoesntContain(f, myText))
.FirstOrDefault()
Now you are free to make DoesntContain as complex or simple as you want. Either use File.ReadAllText or something like:
bool DoesntContain(FileInfo fileInfo, string text) {
using (StreamReader r = fileInfo.OpenText()) {
var contents = r.ReadToEnd();
return !contents.Contains(text);
}
}
You can write the method as extension to get more natural syntax like fi.DoesntContain(...)
Additionally, I suggest using EnumerateFiles instead of GetFiles if the directory can contain many files: there is no need to retrieve them all, if the first one will match.
You can do something like this:
string pattern = "Log*.xml";
var dirInfo = new DirectoryInfo(directory);
var filesThatContains = dirInfo.GetFiles(pattern).
Where(f=>File.ReadAllLines(Path.Combine(directory, f.Name),
Encofing.UTF8).IndexOf(SEARCH_STRING)>=0);
I would do something simpler for a start:
public static string[] FileNamesExcluding(string path, string pattern, string textToExclude)
{
// Put all txt files in root directory into array.
string[] allFilesMatchingPattern = Directory.GetFiles(path, pattern); // <-- Case-insensitive
return allFilesMatchingPattern.SkipWhile(a => a.Contains(textToExclude)).ToArray();
}
To call this method you can do:
FileNamesExcluding(#"C:\", "*.sys", "config").Last();

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

Exclude certain file extensions when getting files from a directory

How to exclude certain file type when getting files from a directory?
I tried
var files = Directory.GetFiles(jobDir);
But it seems that this function can only choose the file types you want to include, not exclude.
You should filter these files yourself, you can write something like this:
var files = Directory.GetFiles(jobDir).Where(name => !name.EndsWith(".xml"));
I know, this a old request, but about me it's always important.
if you want exlude a list of file extension: (based on https://stackoverflow.com/a/19961761/1970301)
var exts = new[] { ".mp3", ".jpg" };
public IEnumerable<string> FilterFiles(string path, params string[] exts) {
return
Directory
.GetFiles(path)
.Where(file => !exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase)));
}
You could try something like this:
var allFiles = Directory.GetFiles(#"C:\Path\", "");
var filesToExclude = Directory.GetFiles(#"C:\Path\", "*.txt");
var wantedFiles = allFiles.Except(filesToExclude);
I guess you can use lambda expression
var files = Array.FindAll(Directory.GetFiles(jobDir), x => !x.EndWith(".myext"))
You can try this,
var directoryInfo = new DirectoryInfo("C:\YourPath");
var filesInfo = directoryInfo.GetFiles().Where(x => x.Extension != ".pdb");
Afaik there is no way to specify the exclude patterns.
You have to do it manually, like:
string[] files = Directory.GetFiles(myDir);
foreach(string fileName in files)
{
DoSomething(fileName);
}
This is my version on the answers I read above
List<FileInfo> fileInfoList = ((DirectoryInfo)new DirectoryInfo(myPath)).GetFiles(fileNameOnly + "*").Where(x => !x.Name.EndsWith(".pdf")).ToList<FileInfo>();
I came across this looking for a method to do this where the exclusion could use the search pattern rules and not just EndWith type logic.
e.g. Search pattern wildcard specifier matches:
* (asterisk) Zero or more characters in that position.
? (question mark) Zero or one character in that position.
This could be used for the above as follows.
string dir = #"C:\Temp";
var items = Directory.GetFiles(dir, "*.*").Except(Directory.GetFiles(dir, "*.xml"));
Or to exclude items that would otherwise be included.
string dir = #"C:\Temp";
var items = Directory.GetFiles(dir, "*.txt").Except(Directory.GetFiles(dir, "*HOLD*.txt"));
i used that
Directory.GetFiles(PATH, "*.dll"))
and the PATH is:
public static string _PATH = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

Categories

Resources