Find all files in first sub directories - c#

I have an application which searches in all directories behind Documents/GameLauncher/ Like this:
var foundApplications = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher", "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".exe") || s.EndsWith(".lnk") || s.EndsWith(".url"));
This works fine but now I only want to find all the applications in the first sub directories of this folder. Like this:
GameLauncher/test/test.exe <--- find this file
GameLauncher/test/test/test.exe <--- Ignore this file
GameLauncher/hello/hello.exe <--- find this file
I have searched around and came up with this:
//Search for first sub directories of path
var folders = Directory.GetDirectories(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher");
IEnumerable<string> foundApplications;
//Use folders to find applications and add them to foundApplications
for (int i = 0; i < folders.Count(); i++)
{
foundApplications += Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher/" + folders[i], "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".exe") || s.EndsWith(".lnk") || s.EndsWith(".url"));
}
//Ends up with error "Use of unassigned local variable 'foundApplications'" when using = instead of += in the forloop above.
foreach (var application in foundApplications){
MessageBox.Show(application.ToString());
}
Does anyone have any tips to solve this problem or even a better way to find those files in the first sub directories of my GameLauncher folder?
Thanks for reading/helping.

Just don't use the "all" option if you don't want all, simple as that.
var path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
#"GameLauncher");
var includedExtensions = new HashSet<string> { ".exe", ".lnk", ".url" };
var files =
from dir in Directory.EnumerateDirectories(path)
from file in Directory.EnumerateFiles(dir)
let extension = Path.GetExtension(file)
where includedExtensions.Contains(extension)
select file;

You should be working with a list instead of an IEnumerable since it will grow dynamically.
var foundApplications = new List<string>();
var folders = Directory.GetDirectories(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher");
//Use folders to find applications and add them to foundApplications
for (int i = 0; i < folders.Count(); i++)
{
foundApplications.AddRange(Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher/" + folders[i], "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".exe") || s.EndsWith(".lnk") || s.EndsWith(".url").ToList());
}
foreach (var application in foundApplications){
MessageBox.Show(application.ToString());
}

If you want to append one IEnumerable to another you need to use Concat. You'll also have to initialize foundApplications to an empty IEnumerable.
var folderPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"GameLauncher");
var folders = Directory.GetDirectories(folderPath);
IEnumerable<string> foundApplications = Enumerable<string>.Empty;
//Use folders to find applications and add them to foundApplications
foreach(var subFolder in folders)
{
string path = Path.Combine(folderPath, subFolder);
foundApplications.Concat(
Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly)
.Where(s => s.EndsWith(".exe") || s.EndsWith(".lnk") || s.EndsWith(".url")));
}
foreach (var application in foundApplications){
MessageBox.Show(application.ToString());
}
Also I'm pretty sure you want to use SearchOption.TopDirectoryOnly not SearchOption.AllDirectories

Related

How to create folders from a list of files by last modified date month wise c#

I want to create folders month wise from a list of files.
I tried below code.
var files = directory.GetFiles()
.Where(file => file.LastWriteTime.Month == date.Month -1);
//create folder for the files (With MonthName)
var year = files.Select(j => j.LastWriteTime.Year).FirstOrDefault();
var month = files.Select(j => j.LastWriteTime.Month).FirstOrDefault();
var newFolderPath = year.ToString() + month.ToString();
var destinationDirec = System.IO.Directory.CreateDirectory(directory + newFolderPath);
foreach (var f in files)
{
// var destFile = System.IO.Path.Combine(directory, destinationDirec);
var path = Path.Combine(destinationDirec.FullName, f.Name);
if (!File.Exists(path))
{
System.IO.File.Move(f.FullName, path);
}
}
The above code gave the list of files for the last month. But I want create folders for the files which are older than the current month.
Can anyone give me a solution?
You can try this code. Maybe with some changes.
//Group files by month. Later you can skip some groups if needed
var fileGroups = directory.GetFiles()
.GroupBy(file => file.LastWriteTime.Month);
foreach (var fileList in fileGroups)
{
var year = fileList.First().LastWriteTime.Year;
var month = fileList.First().LastWriteTime.Month;
var newFolderPath = year.ToString() + month.ToString();
var destinationDirec = System.IO.Directory.CreateDirectory(directory + newFolderPath);
//move files
foreach (var file in fileList)
{
var path = Path.Combine(destinationDirec.FullName, file.Name);
if (!File.Exists(path))
{
System.IO.File.Move(file.FullName, path);
}
}
}
Maybe it's worth to modify GroupBy condition if you have a lot of files from different years.
For example you can use this condition:
GroupBy(file => (397 * file.LastWriteTime.Year) ^ file.LastWriteTime.Month)
This should help, build the fullNewDir value as you need it.
String fullSourceDir = "G:\\Tmp\\Test";
foreach (var fullFileName in Directory.EnumerateFiles(fullSourceDir)){
DateTime lastWriteTime = File.GetLastWriteTime(Path.Combine(fullSourceDir, fullFileName));
String fullNewDir = Path.Combine(fullSourceDir, lastWriteTime.ToString("yyyy-MM-dd_HH-mm"));
if (!Directory.Exists(fullNewDir)){
Directory.CreateDirectory(fullNewDir);
}
String fileName = Path.GetFileName(fullFileName);
System.IO.File.Move(fullFileName, Path.Combine(fullNewDir, fileName));
}

Move files directories and sub directories to another directory Conditionally (Move only Last 5 days created files and directories) in C#

My Source directory "D:\Source"
Destination "D:\Destination"
source directory contains some files and folders with different creation dates,
i want to move all files and folders whose creation date less than last 5 days
for example today is 28/11/2015 and i want to Move all files and folders from source before creating 23/11/205.
i'm searching since 2 days but no success.
here is my Attempt
var sourcePath = "D:\\Source";
var destinationPath = "D:\\Destination";
var dInfo = new DirectoryInfo(sourcePath)
var files = (from filew in dInfo.EnumerateFiles(sourcePath)
orderby filew.CreationTime.Date < DateTime.Now.Date.AddDays(-5) ascending
select filew.Name).Distinct();
var directories = (from filew in dInfo.EnumerateDirectories(sourcePath)
orderby filew.CreationTime.Date < DateTime.Now.Date.AddDays(-5) ascending
select filew.Name).Distinct();
foreach (var dir in directories)
{
var dest = Path.Combine(destinationPath, Path.GetFileName(dir));
Directory.Move(dir, dest);
}
foreach (var file in files)
{
var dest = Path.Combine(destinationPath, Path.GetFileName(file));
File.Move(file, dest);
}
ERROR : Second path fragment must not be a drive or UNC name.
please help me
You have to call EnumerateFiles and EnumerateDirectories without parameters:
dInfo.EnumerateFiles()
dInfo.EnumerateDirectories()
The information about sourcePath is already in the dInfo object. The parameter would be used to apply a filter.
UPDATE:
And the EnumerateFiles() function just returns the file names without pathes. So you should use something like that:
foreach (var file in files)
{
var src = Path.Combine(sourcePath, file);
var dest = Path.Combine(destinationPath, file);
File.Move(src, dest);
}
You would need to do it recursively as there can be sub directories within the directory, where the same rule would apply. Refer to code below.
public static void MoveFilesAndFolders(string sourcePath, string destinationPath)
{
var directories = Directory.GetDirectories(sourcePath);
foreach (var directory in directories)
{
var subDirectory = new DirectoryInfo(directory);
//Create sub directory in the destination folder if the business rules is satisfied
if (DateTime.Today.Subtract(File.GetCreationTime(directory)).Days < 5)
{
var newDestinationDirectory = Directory.CreateDirectory(Path.Combine(destinationPath, subDirectory.Name));
MoveFilesAndFolders(subDirectory.FullName, newDestinationDirectory.FullName);
}
}
foreach (var file in Directory.GetFiles(sourcePath))
{
var fileName = Path.GetFileName(file);
//Copy the file to destination folder if the business rule is satisfied
if (!string.IsNullOrEmpty(fileName))
{
var newFilePath = Path.Combine(destinationPath, fileName);
if (!File.Exists(newFilePath) && (DateTime.Today.Subtract(File.GetCreationTime(file)).Days < 5)))
{
File.Move(file, newFilePath);
}
}
}
}

How to get files from exact subdirectories

I've managed to get files out of "root" folder subdirectories, but I also get files from these subdirectories directories2, which I don't want to.
Example: RootDirectory>Subdirectories (wanted files)>directories2 (unwanted files)
I've used this code:
public void ReadDirectoryContent()
{
var s1 = Directory.GetFiles(RootDirectory, "*", SearchOption.AllDirectories);
{
for (int i = 0; i <= s1.Length - 1; i++)
FileInfo f = new FileInfo(s1[i]);
. . . etc
}
}
Try this :
var filesInDirectSubDirs = Directory.GetDirectories(RootDirectory)
.SelectMany(d=>Directory.GetFiles(d));
foreach(var file in filesInDirectSubDirs)
{
// Do something with the file
var fi = new FileInfo(file);
ProcessFile(fi);
}
The idea is to first select 1st level of subdirectories, then "aggregate" all files using Enumerable.SelectMany method
You have to change SearchOption.AllDirectories to SearchOption.TopDirectoryOnly, because the first one means that it gets the files from the current directory and all the subdirectories.
EDIT:
The op wants to search in direct child subdirectories, not the root
directory.
public void ReadDirectoryContent()
{
var subdirectories = Directory.GetDirectories(RootDirectory);
List<string> files = new List<string>();
for(int i = 0; i < subdirectories.Length; i++)
files.Concat(Directory.GetFiles(subdirectories[i], "*", SearchOption.TopDirectoryOnly));
}

How can recursively search directories with multiple wildcards?

Using C# (.NET), how can I search a file system given a directory search mask like this: (?)
\\server\Scanner\images\*Images\*\*_*
For example, I need to first find all top-level directories:
\\server\Scanner\images\Job1Images
\\server\Scanner\images\Job2Images
...then I need to procede further with the search mask:
\\server\Scanner\images\Job1Images\*\*_*
\\server\Scanner\images\Job2Images\*\*_*
This doesn't seem too complicated but I can't figure it out for the life of me...
As mentioned above, I'm using C# and .NET. The search can be trying to locate directories or files. (i.e. *.txt, or <*Directory>)
Like this:
Top Level Directories:
//get Top level
string[] TopLevel = Directory.GetDirectories(path);
And then you will have to do a resursive function of this folders using wildcard pattern,
for example:
// Only get subdirectories that begin with the letter "p."
string pattern = "p*";
string[] dirs = folder.GetDirectories(path, pattern);
I suggest you play with wildcards to get the array output and you will figure out
which is the best way, if using resursive function or directly quering paths.
Edit: Ahh, new functionality with .NET 4 so you don't have to do a recursive function (Thanks Matthew Brubaker)
IEnumerable<String> matchingFilePaths2 = System.IO.Directory.EnumerateFiles(#"C:\some folder to start in", filePatternToMatchOn, System.IO.SearchOption.AllDirectories);
First Answer:
//get all files that have an underscore - searches all folders under the start folder
List<String> matchingFilePaths = new List<string>();
String filePatternToMatchOn = "*_*";
FileUtilities.GetAllFilesMatchingPattern(#"C:\some folder to start in", ref matchingFilePaths, filePatternToMatchOn);
...
public static void GetAllFilesMatchingPattern(String pathToGetFilesIn, ref List<String> fullFilePaths, String searchPattern)
{
//get all files in current directory that match the pattern
String[] filePathsInCurrentDir = Directory.GetFiles(pathToGetFilesIn, searchPattern);
foreach (String fullPath in filePathsInCurrentDir)
{
fullFilePaths.Add(fullPath);
}
//call this method recursively for all directories
String[] directories = Directory.GetDirectories(pathToGetFilesIn);
foreach (String path in directories)
{
GetAllFilesMatchingPattern(path, ref fullFilePaths, searchPattern);
}
}
public static IEnumerable<string> GetImages()
{
//For each "*Image" directory
foreach (var jobFolder in Directory.EnumerateDirectories(#"\\server\Scanner\images", "*Images"))
{
//For each first level subdirectory
foreach (var jobSubFolder in Directory.EnumerateDirectories(jobFolder))
{
//Enumerate each file containing a '_'
foreach (var filePath in Directory.EnumerateFiles(jobSubFolder, "*_*", SearchOption.TopDirectoryOnly))
{
yield return filePath;
}
}
}
}
Only the files from the first level subdirectories of each "*Image" directory are enumerated.
Finally you can use it with:
foreach (var path in GetImages())
{
Console.WriteLine(path);
}
There is a C# procedure where you can search folder by path pattern with wildcards like * and ?.
Example if path pattern C:\Folder?*\Folder2 is passed to the procedru, then a list of folder path will be returned
C:\Folder1\A\Folder2
C:\FolderA\B\Folder2
...
and so on
static List<string> GetFoldersByPathPattern(string folderPathPattern)
{
List<string> directories = new List<string>();
directories.Add("");
string[] folderParts = folderPathPattern.Split(new char[] { '\\' }, StringSplitOptions.None);
foreach (string folderPart in folderParts)
{
if (folderPart.Contains('*') || folderPart.Contains('?'))
{
List<string> newDirectories = new List<string>();
foreach (string directory in directories)
{
foreach (string newDirectory in Directory.GetDirectories(directory, folderPart))
{
newDirectories.Add(newDirectory);
}
}
directories = newDirectories;
}
else
{
for (int i = 0; i < directories.Count(); i++)
{
directories[i] = directories[i] + folderPart + "\\";
}
}
}
return directories;
}

Exact file extension match with GetFiles()?

I'd like to retrieve a list of files whose extensions match a specified string exactly.
DirectoryInfo di = new DirectoryInfo(someValidPath);
List<FileInfo> myFiles = new List<FileInfo>();
foreach (FileInfo fi in di.GetFiles("*.txt"))
{
myFiles.Add(fi);
}
I get the files with extension *.txt but I also get files with the extension *.txtx, so what I've coded amounts to getting the files whose extension starts with txt.
This isn't what I want. Do I need to grab all of the filenames and do a regular expression match to "\\.txt$" (I think), or test each filename string with .EndsWith(".txt"), etc., to accomplish this?
Thanks!
Somewhat of a workaround, but you can filter out exact matches with the Where extesion method:
foreach (FileInfo fi in di.GetFiles("*.txt")
.Where(fi => string.Compare(".txt", fi.Extension, StringComparison.OrdinalIgnoreCase) == 0))
{
myFiles.Add(fi);
}
Note that this will make a case insensitive matching of the extension.
Using the AddRange feature of lists instead of doing the foreach loop and calling Add for each item returned by the expression below (which I save into the variable list).
var list = di.GetFiles("*.txt").Where(f => f.Extension == ".txt");
myFiles.AddRange(list);
I'm presuming you were just showing us a snippet of your code and myFiles already had values in it, if not, you could do instead.
List<FileInfo> myFiles = di.GetFiles("*.txt").Where(f => f.Extension == ".txt").ToList();
Regex might be overkill. Use the extension on FileInfo.
foreach (FileInfo fi in di.GetFiles("*.txt").Where(f => f.Extension == ".txt"))
{
myFiles.Add(fi);
}
Try this:
DirectoryInfo di = new DirectoryInfo(someValidPath);
List<FileInfo> myFiles =
(
from file in di.GetFiles("*.txt")
where file.Extension == ".txt"
select file
).ToList();
DirectoryInfo di = new DirectoryInfo(someValidPath);
List<FileInfo> myFiles = new List<FileInfo>();
foreach (FileInfo fi in di.GetFiles("*.txt"))
{
if (fi.Extension == ".txt")
myFiles.Add(fi);
}
Couldn't you just add an if and check the last four characters of the filename?
If you are using C# 2.0
Isn't easier ?
string fileExtensionFilter = "*.txt";
DirectoryInfo di = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
List<FileInfo> myFiles = new List<FileInfo>();
foreach (FileInfo fi in di.GetFiles(fileExtensionFilter))
{
if (fi.Extension == fileExtensionFilter.Substring(1)) myFiles.Add(fi);
}
I had a user-supplied pattern so many of the other answers didn't suit me. I ended up with this more general purpose solution:
public string[] GetFiles(string path, string pattern)
{
bool lastWildIsHook = false;
if(pattern.EndsWith("?"))
{
pattern = pattern.Substring(0, pattern.Length - 1);
lastWildIsHook = true;
}
var lastWildIndex = Math.Max(pattern.LastIndexOf("*"), pattern.LastIndexOf("?"));
var endsWith = pattern.Length > lastWildIndex ? pattern.Substring(lastWildIndex + 1) : pattern;
if(!lastWildIsHook)
return Directory.GetFiles(path, pattern).Where(p => p.EndsWith(endsWith)).ToArray();
else
return Directory.GetFiles(path, pattern).Where(p => p.EndsWith(endsWith) || p.Substring(0, p.Length - 1).EndsWith(endsWith)).ToArray();
}

Categories

Resources