How to read all items on the Start menu - c#

How can I get a list of all the shortcuts/programs in the start menu using C#?
I had to do this recently and surprisingly couldn't find a question for it anywhere on SO so thought I would share how I did it.

The following code reads the files from the special folder then LINQ to split the full pathname based upon the backslash character and takes the last element to get just the filename. It then splits the filename based upon the full stop (period) character and takes the first element to get the filename minus the extension.
Note the only difference between the All Users and Current User is the SpecialFolder name which is either CommonStartMenu or StartMenu.
Current User Start Menu
string startmenu = Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);
IEnumerable<string> files = Directory.GetFiles(startmenu, "*.*", SearchOption.AllDirectories).Select(x => x.Split('\\').Last().Split('.').First());
foreach (var file in files)
{
Console.WriteLine(file);
}
Console.ReadKey();
All Users Start Menu
string startmenu = Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu);
IEnumerable<string> files = Directory.GetFiles(startmenu, "*.*", SearchOption.AllDirectories).Select(x => x.Split('\\').Last().Split('.').First());
foreach (var file in files)
{
Console.WriteLine(file);
}
Console.ReadKey();

Related

c# - Remove old Files from FileInfo list

I have a File-Info-List of more than 200 log-files from a directory.
Most of the files need to be in the list, but there are a few lists that should be ignored.
Here is an example of the File-List:
A300a1_ContentLink.log
A301a20_ContentLink.log
A1_4a0_ContentLink.log
B200a101_ContentLink.log
B200a101_ContentLink_20221208_115905.log
B200a101_ContentLink_20221208_115907.log
B200a101_ContentLink_20221208_120647.log
B201a1_ContentLink.log
B202a0_ContentLink.log
Explanation of the file name:
The first chars refer to a room (e.g. room A300 or A1). A room could have any description, eg B200, CXS2 or only CDD, the next to a device-name (e.g. device a1 oder device a20). Each device starts with a, followed by 1-3 digits. Last part of each file is "_ContentLink" .
All files with further ending, like _202211208_115905 are duplicates of older versions, that are needed in other programs, but not in my List.
My problem is that I only need the newest File of each logfile in my File-Info-List.
I initialized a FileInfo[] allFiles that contains all of the files of the directory.
Next I initialized a new FileInfo[] in which I would like to store only the newest version of each file.
My first attempt was to compare the LastWrite time
FileInfo currentFile = allFiles[0];
foreach (FileInfo file in allFiles)
{
if (file.LastWriteTime > currentFile.LastWriteTime)
{
currentFile = file;
}
}
But I only get back the latest file of the whole folder.
Now, I am thinking about to use Regular Expressions insteadt of .LastWriteTime, to exclude all Files that have a suffix after ContentLink.
But I don't know how and how to remove the outdated files from the list with all files (or transfer only the relevatn to a new File Info[]-List)
Thank you in advance for your ideas.
You can use a LINQ query to:
extract the name and time part from each file name
group the files by name and
select the latest (maximum) file by time
Something like :
var regex=new Regex("^(.*?)_ContentLink(.*?).log");
var latest=allFiles.Select(f=>{
var parts=regex.Match(f.Name);
return new {
File=f,
Name=parts.Groups[1].ToString(),
Date=parts.Groups[2].ToString()
};
})
.GroupBy(f=>f.Name)
.Select(g=>g.MaxBy(f=>f.Date).File)
.ToArray();
foreach(var file in latest)
{
Console.WriteLine(file.Name);
}
This produces
A300a1_ContentLink.log
A301a20_ContentLink.log
A1_4a0_ContentLink.log
B200a101_ContentLink_20221208_120647.log
B201a1_ContentLink.log
B202a0_ContentLink.log
MaxBy was added in .NET 6. Before that you can use the equivalent method from the MoreLINQ library.
The regular expression captures the smallest possible string before _ContentLink in the first group (.*?) and the smallest possible date part in the second group.
You could get a bit fancier and use different regular expressions to capture the name and time part. Combined with local functions, this results in a somewhat cleaner query:
var nameRex=new Regex("^(.*?)_ContentLink.*.log");
var timeRex=new Regex("^.*_ContentLink(.*?).log");
string NamePart(FileInfo f)
{
return nameRex.Match(f.Name).Groups[1].ToString();
}
string TimePart(FileInfo f)
{
return timeRex.Match(f.Name).Groups[1].ToString();
}
var latest=allFiles
.GroupBy(NamePart)
.Select(g=>g.MaxBy(TimePart))
.ToArray();

Get the first character from the filename in a filepath

I have an array of filepaths in a directory and I'm trying to move certain files based on alphabet.
string[] filePaths = Directory.GetFiles(#"C:\user\desktop\folder", "*.txt");
foreach (var file in filePaths)
{
if (file.StartsWith("A"))
{
//Move file
The obvious problem is that file.StartWith is pulling the entire filepath (C:\user\desktop\folder\Albert.txt) Which doesn't start with 'A'
So what would be the best way to just target the start of the actual file?
Thanks in advance.
I got it working with Path.GetFileName as per the suggestion by #Jimi
What about this code
var dir = new DirectoryInfo(#"C:\user\desktop\folder");
var files = dir.GetFiles();
foreach (var file in files)
{
if(file.Name.StartsWith("A"))
{
//Move file
You say you're looking to move files by alphabet- if you mean to put files into a folder whose name is the same as the first char of the filename then perhaps:
var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); //don't hard code the path to the desktop
var root = Path.Combine(desktop, "foldernamehere"); //use path.combine to build paths
foreach(var f in directory.EnumerateFiles(root, "*.txt")){ //prefer EnumerateFiles over GetFiles
var filename = Path.GetFileName(f);
var dest = Path.Combine(root, filename.Remove(1));
Directory.CreateDirectory(dest); //safe to call even if exists, ensures exists
File.Move(f, Path.Combine(dest, filename));
}
See comments for more info
If you have a string that represents a full filename (or directory name), and you want the name without the directory, consider to use Path.GetFileName
string fullFileName = "C:\user\desktop\folder\Albert.txt";
string fileName = Path.GetDirectoryName(fullFileName);
fileName will be "Albert.txt"
With this in mind, your query will be easy:
IEnumerable<string> fullFileNames = ...
char startChar = 'A';
IEnumerable<string> fileNamesThatStartWithStartChar = fullFileNames
.Where(fileName => Path.GetDirectoryName(fileName).StartsWitch(startChar));
In words: from every fileName in the sequence of fullFileName, take the fileName without the directory information. Keep the fileName if this "fileName without directory information" starts with the startChar.
Note: StartsWitch(char) is case sensitive. If you want to check case insensitive, use String.StartsWitch(string, stringComparison)
There's room for improvement!
If you think that there might be a chance that you won't be using all information of all files, consider to use Directory.EnymerateFiles instead of GetFiles. This way, if at the end of your LINQ you decide to use only 3 of the fetched files (or worse: FirstOrDefault(), or Any()), you won't have fetched all files.

Search for file in c#

I wanted to search for files in c# begin with a string.
I followed the code in the internet
string[] dirs = Directory.GetFiles(#"c:\", "c*");
but instead of finding "c", I want to find files contains a string (i mean the file name for example contain.txt and contain.pdf both has "contain") i created. Here is my code
string filetofind;
string[] dirs = Directory.GetFiles(#"c:\", filetofind + "*");
but it just not working, is there anyway else?
If
I want to find files contains a string i created
means you want to check file's content (not name) You have to load the file, e.g. (assuming stringToFind doesn't have line breaks)
string[] dirs = Directory
.EnumerateFiles(#"c:\", "*.txt"); // all txt files (put the right wildcard)
.Where(file => File
.ReadLines(file) // with at least one line
.Any(line => line.Contains(stringToFind))) // which contains stringToFind
.ToArray();
Edit: In case you want files' names which contain c, e.g. "mycode.txt", "Constraints.dat" etc. (but not "demo.com" since c is in the file's extension); you can try *c*.* wild card: file name contains c with any extension:
string[] dirs = Directory
.GetFiles(#"c:\", $"*{filetofind}*.*");
In case of elaborated condition, when standard wildcard in not enough, just add Where:
string[] dirs = Directory
.EnumerateFiles(#"c:\", "*.*")
.Where(path => Your_Condition(Path.GetFileNameWithoutExtension(path)))
.ToArray();
For instance, let's test file name for small (not capital) letter c
string[] dirs = Directory
.EnumerateFiles(#"c:\", "*.*")
.Where(path => Path.GetFileNameWithoutExtension(path).Contains('c'))
.ToArray();
To find files where the file name contains "foo", use
var files = Directory.EnumerateFiles("C:\\dir", "*foo*", SearchOption.AllDirectories);
To find files where the text content contains "foo" use:
var files = Directory.EnumerateFiles("C:\\dir", "*", SearchOption.AllDirectories)
.Where(f => File.ReadAllText(f).Contains("foo"));
This should work, but it will read the entire file as text until you stop enumerating the list of files, so you might want to filter the file list search pattern before reading them. You could also write your own method to inspect each file rather than reading the entire thing into memory for every file.
Substitute SearchOption.AllDirectories for SearchOption.TopDirectoryOnly if you only want to search that directory, and not recursively search subdirectories.
if the file you want find starts with "filetofind" then code is correct. But if "filetofind" comes somewhere between the complete file name then your code must change to
string filetofind;
string[] dirs = Directory.GetFiles(#"c:\", "*filetofind*");

Buffer file names in a given directory

I'm trying to find a way to buffer FileNames from a given directory in C#. By this I mean:
Given directory
C:/MyDir
Which contains files:
File1_orig.txt
File1_edited.txt
File2_orig.txt
File2_edited.txt
...
Filen_orig.txt
Filen_edited.txt
I want to store the filenames(not the whole filepath, just the filename, e.g. String[] filename = Filen_orig.txt) into temporary strings and run a simple comparison on them to see if they contain a target string.
I would like to pass the strings into:
while(STILL FILES IN DIRECTORY)
{
string[] exFileName = {BUFFER FILENAME HERE}
string[] words = exFileName.Split('_');
string[] toCompare = "edited";
bool result;
foreach (string word in words)
{
Console.WriteLine(word);
bool result = toCompare.Equals(word, StringComparison.OrdinalIgnoreCase);
if (result)
{
Console.WriteLine("success");
}
}
Console.ReadLine();
To check to see if the file being examined is edited (*_edited.txt) or an original (*_original.txt), and, if the file is edited, further process the file.
Does anyone know how to automate a filepath read?
Thank you very much.
if you want to see if any files contain the _edited bit, you can use:
bool success = Directory.GetFiles(#"c:\MyDir").Any(p => p.Contains("_edited"));
I'm making a bit of a guess this is what you want because your code isn't very clear (nor is your description)
Edit: to show all edited files:
foreach(var file in Directory.GetFiles(#"c:\MyDir").Where(p => p.Contains("_edited")))
{
Console.WriteLine(" {0}: edited", file);
}
Also, must be using "System.Linq"
How about DirectoryInfo.GetFiles?
DirectoryInfo di = new DirectoryInfo(#"c:\");
// Get only subdirectories that contain the letter "p."
FileInfo[] files= di.GetFiles("*.txt");
foreach (FileInfo fi in files)
{
string exFileName = fi.FileName;
...
}

Regex to parse out filename and partial path, conditionally

I have a C# app that uses the search functions to find all files in a directory, then shows them in a list. I need to be able to filter the files based on extension (possible using the search function) and directory (eg, block any in the "test" or "debug" directories from showing up).
My current code is something like:
Regex filter = new Regex(#"^docs\(?!debug\)(?'display'.*)\.(txt|rtf)");
String[] filelist = Directory.GetFiles("docs\\", "*", SearchOption.AllDirectories);
foreach ( String file in filelist )
{
Match m = filter.Match(file);
if ( m.Success )
{
listControl.Items.Add(m.Groups["display"]);
}
}
(that's somewhat simplified and consolidated, the actual regex is created from a string read from a file and I do more error checking in between.)
I need to be able to pick out a section (usually a relative path and filename) to be used as the display name, while ignoring any files with a particular foldername as a section of their path. For example, for these files, only ones with +s should match:
+ docs\info.txt
- docs\data.dat
- docs\debug\info.txt
+ docs\world\info.txt
+ docs\world\pictures.rtf
- docs\world\debug\symbols.rtf
My regex works for most of those, except I'm not sure how to make it fail on the last file. Any suggestions on how to make this work?
Try Directory.GetFiles. This should do what you want.
Example:
// Only get files that end in ".txt"
string[] dirs = Directory.GetFiles(#"c:\", "*.txt", SearchOption.AllDirectories);
Console.WriteLine("The number of files ending with .txt is {0}.", dirs.Length);
foreach (string dir in dirs)
{
Console.WriteLine(dir);
}
^docs\\(?:(?!\bdebug\\).)*\.(?:txt|rtf)$
will match a string that
starts with docs\,
does not contain debug\ anywhere (the \b anchor ensures that we match debug as an entire word), and
ends with .txt or .rtf.

Categories