If exists unallowed files, show messagebox with their name - c#

I have this code:
HashSet<string> allowedFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"file1.dll",
"file2.dll",
"file3.exe"
};
DirectoryInfo directory = new DirectoryInfo(Directory.GetCurrentDirectory());
bool containsNonAllowedFiles = directory.EnumerateFiles().Any(file => !allowedFiles.Contains(file.Name));
if (containsNonAllowedFiles == true)
{
Message.Warning("Unallowed files found ! Please remove them.");
return;
}
But I want to show filename, which is unallowed, how can I do it?
For example I have folder with these files: file1.dll, file2.dll, file3.exe, file4.exe, When I launch the app it must print for me Unallowed files found ! Please remove file4.exe and start app again. Thanks in advance

Use the Except method from Linq to produce the list of unallowed file names.
var disallowedFiles = directory.EnumerateFiles()
.Select(fi => fi.Name)
.Except(allowedFiles, StringComparer.OrdinalIgnoreCase)
.ToList();

DirectoryInfo directory = new DirectoryInfo(Directory.GetCurrentDirectory());
List<FileInfo> files = directory.GetFiles().ToList();
List<FileInfo> unAllowed = files.FindAll(f => !allowedFiles.Contains(f.Name));
if (unAllowed.Count > 0)
{
string notAllowedFiles = "";
unAllowed.ForEach(f => notAllowedFiles += f.Name + ",");
Message.Warning("Unallowed files found ! Please remove " + notAllowedFiles);
return;
}

You can use Where instead of the early Any:
var nonAllowedFilesNames = directory.EnumerateFiles()
.Select(file => file.Name)
.Where(fileName => !allowedFiles.Contains(fileName));
if(nonAllowedFilesNames.Any())
{
string unallowedFiles = String.Join(",", nonAllowedFilesNames);
Message.Warning("Unallowed files found ! Please remove: " + unallowedFiles);
}

You must get the list of unallowed files. You can do it like this :
List<String> nonAllowedFiles = directory.EnumerateFiles().FindAll(file => !allowedFiles.Contains(file.Name));
and then you can process it like this :
foreach (String file in nonAllowedFiles ) {
Message.Warning("Unallowed files found ! Please remove " + file + " and start app again");
}
return;

Related

C# How limit child folders results with Directory.GetPath LINQ

I have this function:
var dupeFiles = Directory.EnumerateFiles(strPath, "*", SearchOption.AllDirectories)
.Select(fullPath => new
{
Name = Path.GetFileName(fullPath),
FullPath = fullPath
})
.GroupBy(file => file.Name)
.Where(fileGroup => fileGroup.Count() > 1);
foreach (var dupeGroup in dupeFiles)
{
using (System.IO.StreamWriter file =
new System.IO.StreamWriter(#"DupeFiles.txt", true))
{
file.WriteLine(dupeGroup.Key);
}
foreach (var dupeFile in dupeGroup)
{
using (System.IO.StreamWriter file =
new System.IO.StreamWriter(#"DupeFiles.txt", true))
{
file.WriteLine($" {dupeFile.FullPath}");
}
}
}
But im getting this result:
FILE.TXT
...\RootFolder\Folder1\Child1\AnotherChild\FILE.TXT
...\RootFolder\Folder1\Child2\AnotherChild\FILE.TXT
...\RootFolder\Folder1\Child3\FILE.TXT
...\RootFolder\Folder2\Child3\FILE.TXT
...\RootFolder\Folder2\Child2\AnotherChild\FILE.TXT
How limit the result for the same file path from folder1 and folder2 (or more, this same child level)? In that case, i just want the results:
FILE.TXT
...\RootFolder\Folder1\Child2\AnotherChild\FILE.TXT
...\RootFolder\Folder2\Child2\AnotherChild\FILE.TXT
Thank you!
Thank you all replys, but it stills don't helps. Maybe i can't tell you what exactly i need, so look those real pic:
As you can see, the first file: NMS_REALITY_GCTECHNOLOGYTABLE.MBIN are repeated on 3 folders:
LessOverHeat10 ...
Reduced Launch Cost...
_BettterFreighter...
Thats all right, because as you can see, the same file was on (root) folders different.
But another other files, PLANTINTERACTION.ENTITY.MBIN, repeats on a lot of others folders, but inside the same folder:
_FASTER_FARMING_X50.
This part is wrong. I would lik to ignore (not list) all those files, because its for the same folder. I just would like to list, or mark them as conflicted, if its at the same path, but for different root folder.
Its better now? Thank you so much, sorry if can't explain right my needs.
Count on you, thanks!!!
Make a ParentPath attribute and group by that then select what you want from every parentDirectory by skipping all you don't want.
var dupeFiles = Directory.EnumerateFiles(strPath, "*", SearchOption.AllDirectories)
.Select(fullPath => new
{
Name = Path.GetFileName(fullPath),
FullPath = fullPath,
ParentPath = GetParentPath(fullPath)
}).GroupBy(file => file.ParentPath)
.Select(parentDirectory => parentDirectory
.SkipWhile((childFile, index) => index != 1)
.First()
);
StreamWriter fileWriter = new StreamWriter(#"DupeFiles.txt", true);
foreach(var aFile in dupeFiles.ToList())
Console.WriteLine(aFile.FullPath);
...
private string GetParentPath(string fullPath)
{
string [] strArr = fullPath.Split('\\');
string parentPath = strArr[0] + '\\' + strArr[1] + '\\' + strArr[2] + '\\' + strArr[3] + '\\' + strArr[4] + '\\' + strArr[5];
//Console.WriteLine("parentPath: " + parentPath);
return parentPath;
}
...
Edited answer using double foreach and retaining IGrouping.Key
string strPath = "C:\\Users\\Luke\\Desktop\\RootFolder";
var dupeFiles = Directory.EnumerateFiles(strPath, "*", SearchOption.AllDirectories)
.Select(fullPath => new
{
Name = Path.GetFileName(fullPath),
FullPath = fullPath,
}).GroupBy(file => GetParentPath(file.FullPath))
.Select(parentDirectory =>
parentDirectory.SkipWhile((childFile, index) => index != 1).First()
).GroupBy(file => file.Name, file => file.FullPath);
foreach(var dupeGroup in dupeFiles)
{
Console.WriteLine("key is: " + dupeGroup.Key);
foreach (var dupeFile in dupeGroup)
{
Console.WriteLine(dupeFile);
}
}
/*example output
key is: FILE.txt
C:\Users\Luke\Desktop\RootFolder\Folder1\Child2\AnotherChild\FILE.txt
C:\Users\Luke\Desktop\RootFolder\Folder2\Child2\AnotherChild\FILE.txt
*/

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

Find all files in first sub directories

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

Get file using file name. there may be multiple files with similar names _1, _2 etc

I am using the following to get the size of a file
FileInfo(filePath).Length
which of course works.
The file path is something like
Live\Sites\User\297387\XYZ - ABC
but an issue arises when the file is a duplicate
Live\Sites\User\297387\XYZ - ABC_2
Is there a way I can get the latest version of the file that name matches
Live\Sites\User\297387\XYZ - ABC
So I have the following files
Live\Sites\User\297387\XYZ - ABC
Live\Sites\User\297387\XYZ - ABC_1
Live\Sites\User\297387\XYZ - ABC_2
and I need to get the latest one that matches
Live\Sites\User\297387\XYZ - ABC
You can use the Path class and LINQ:
string fileName = Path.GetFileName(filePath);
string dir = Path.GetDirectoryName(filePath);
var latestFile = new DirectoryInfo(dir)
.EnumerateFiles("*.*", SearchOption.TopDirectoryOnly)
.Where(file => file.Name.StartsWith(fileName))
.OrderByDescending(file => file.LastAccessTime)
.First();
long len = latestFile.Length;
If you dont want to check the last access time but the number behind _ you can use this query:
var latestFile = new DirectoryInfo(dir)
.EnumerateFiles("*.*", SearchOption.TopDirectoryOnly)
.Where(file => file.Name.StartsWith(fileName))
.Select(file =>
{
int index = file.Name.LastIndexOf('_');
string vStr = "0";
if(index >= 0)
vStr = file.Name.Substring(index + 1);
int version;
if(!int.TryParse(vStr, out version))
version = 0;
return new { file, version };
})
.OrderByDescending(xFile => xFile.version)
.Select(xFile => xFile.file)
.First();
Use FileSystemWatcher
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = " Live\Sites\User\297387\XYZ";
watcher.Changed += new FileSystemEventHandler(OnChanged);
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
}
This LinQ Query get the last file in Directory:
var lastFile = (from a in directoryInfo.EnumerateFiles()
orderby a.CreationTime descending
select a).FirstOrDefault();
or
var lastFile = (from a in directoryInfo.EnumerateFiles()
orderby a.CreationTime
select a).LastOrDefault();
This is my "cleanest" first-to-mind solution:
string regx = "file"; // replace this with your actual "base" file name
var f = Directory.EnumerateFiles("C:\\") // replace with your directory path
.Where(fn=>
System.Text.RegularExpressions.Regex.IsMatch(fn, regx, System.Text.RegularExpressions.RegexOptions.IgnoreCase))
.Select(fn=>new FileInfo(fn))
.Aggregate( (f1,f2) => f1.LastWriteTime> f2.LastWriteTime? f1 : f2);
This will match all files in C:\ that has the word file in it - then select the most recently written file.

How to find the Filename with the latest version in C#

I have a folder that is filled with dwg files so I just need to find the latest version of a File or if a File has no versions then copy it to a directory. For example here are three files:
ABBIE 08-10 #6-09H4 FINAL 06-12-2012.dwg
ABBIE 08-10 #6-09H4 FINAL 06-12-2012_1.dwg
ABBIE 08-10 #6-09H4 FINAL 06-12-2012_2.dwg
Notice the difference is one file has a _1 and another has a _2 so the latest file here is the _2. I need to keep the latest file and copy it to a directory. Some files will not have different versions so those can be copied. I cannot focus on the creation date of the file or the modified date because in many instances they are the same so all I have to go on is the file name itself. I'm sure there is a more efficient way to do this than what I will post below.
DirectoryInfo myDir = new DirectoryInfo(#"H:\Temp\Test");
var Files = myDir.GetFiles("*.dwg");
string[] fileList = Directory.GetFiles(#"H:\Temp\Test", "*FINAL*", SearchOption.AllDirectories);
ArrayList list = new ArrayList();
ArrayList WithUnderscores = new ArrayList();
string nameNOunderscores = "";
for (int i = 0; i < fileList.Length; i++)
{
//Try to get just the filename..
string filename = fileList[i].Split('.')[0];
int position = filename.LastIndexOf('\\');
filename = filename.Substring(position + 1);
filename = filename.Split('_')[0];
foreach (FileInfo allfiles in Files)
{
var withoutunderscore = allfiles.Name.Split('_')[0];
withoutunderscore = withoutunderscore.Split('.')[0];
if (withoutunderscore.Equals(filename))
{
nameNOunderscores = filename;
list.Add(allfiles.Name);
}
}
//If there is a number after the _ then capture it in an ArrayList
if (list.Count > 0)
{
foreach (string nam in list)
{
if (nam.Contains("_"))
{
//need regex to grab numeric value after _
var match = new Regex("_(?<number>[0-9]+)").Match(nam);
if (match.Success)
{
var value = match.Groups["number"].Value;
var number = Int32.Parse(value);
WithUnderscores.Add(number);
}
}
}
int removedcount = 0;
//Whats the max value?
if (WithUnderscores.Count > 0)
{
var maxval = GetMaxValue(WithUnderscores);
Int32 intmax = Convert.ToInt32(maxval);
foreach (FileInfo deletefile in Files)
{
string shorten = deletefile.Name.Split('.')[0];
shorten = shorten.Split('_')[0];
if (shorten == nameNOunderscores && deletefile.Name != nameNOunderscores + "_" + intmax + ".dwg")
{
//Keep track of count of Files that are no good to us so we can iterate to next set of files
removedcount = removedcount + 1;
}
else
{
//Copy the "Good" file to a seperate directory
File.Copy(#"H:\Temp\Test\" + deletefile.Name, #"H:\Temp\AllFinals\" + deletefile.Name, true);
}
}
WithUnderscores.Clear();
list.Clear();
}
i = i + removedcount;
}
else
{
//This File had no versions so it is good to be copied to the "Good" directory
File.Copy(#"H:\Temp\SH_Plats\" + filename, #"H:\Temp\AllFinals" + filename, true);
i = i + 1;
}
}
I've made a Regex based solution, and apparently come late to the party in the meantime.
(?<fileName>[A-Za-z0-9-# ]*)_?(?<version>[0-9]+)?\.dwg
this regex will recognise the fileName and version and split them into groups, a pretty simple foreach loop to get the most recent files in a dictionary (cos I'm lazy) and then you just need to put the fileNames back together again before you access them.
var fileName = file.Key + "_" + file.Value + ".dwg"
full code
var files = new[] {
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012.dwg",
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012_1.dwg",
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012_2.dwg",
"Second File.dwg",
"Second File_1.dwg",
"Third File.dwg"
};
// regex to split fileName from version
var r = new Regex( #"(?<fileName>[A-Za-z0-9-# ]*)_?(?<version>[0-9]+)?\.dwg" );
var latestFiles = new Dictionary<string, int>();
foreach (var f in files)
{
var parsedFileName = r.Match( f );
var fileName = parsedFileName.Groups["fileName"].Value;
var version = parsedFileName.Groups["version"].Success ? int.Parse( parsedFileName.Groups["version"].Value ) : 0;
if( latestFiles.ContainsKey( fileName ) && version > latestFiles[fileName] )
{
// replace if this file has a newer version
latestFiles[fileName] = version;
}
else
{
// add all newly found filenames
latestFiles.Add( fileName, version );
}
}
// open all most recent files
foreach (var file in latestFiles)
{
var fileToCopy = File.Open( file.Key + "_" + file.Value + ".dwg" );
// ...
}
You can use this Linq query with Enumerable.GroupBy which should work(now tested):
var allFiles = Directory.EnumerateFiles(sourceDir, "*.dwg")
.Select(path => new
{
Path = path,
FileName = Path.GetFileName(path),
FileNameWithoutExtension = Path.GetFileNameWithoutExtension(path),
VersionStartIndex = Path.GetFileNameWithoutExtension(path).LastIndexOf('_')
})
.Select(x => new
{
x.Path,
x.FileName,
IsVersionFile = x.VersionStartIndex != -1,
Version = x.VersionStartIndex == -1 ? new Nullable<int>()
: x.FileNameWithoutExtension.Substring(x.VersionStartIndex + 1).TryGetInt(),
NameWithoutVersion = x.VersionStartIndex == -1 ? x.FileName
: x.FileName.Substring(0, x.VersionStartIndex)
})
.OrderByDescending(x => x.Version)
.GroupBy(x => x.NameWithoutVersion)
.Select(g => g.First());
foreach (var file in allFiles)
{
string oldPath = Path.Combine(sourceDir, file.FileName);
string newPath;
if (file.IsVersionFile && file.Version.HasValue)
newPath = Path.Combine(versionPath, file.FileName);
else
newPath = Path.Combine(noVersionPath, file.FileName);
File.Copy(oldPath, newPath, true);
}
Here's the extension method which i'm using to determine if a string is parsable to int:
public static int? TryGetInt(this string item)
{
int i;
bool success = int.TryParse(item, out i);
return success ? (int?)i : (int?)null;
}
Note that i'm not using regex but string methods only.
Try this
var files = new My.Computer().FileSystem.GetFiles(#"c:\to\the\sample\directory", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dwg");
foreach (String f in files) {
Console.WriteLine(f);
};
NB: Add a reference to Microsoft.VisualBasic and use the following line at the beginning of the class:
using My = Microsoft.VisualBasic.Devices;
UPDATE
The working sample[tested]:
String dPath=#"C:\to\the\sample\directory";
var xfiles = new My.Computer().FileSystem.GetFiles(dPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dwg").Where(c => Regex.IsMatch(c,#"\d{3,}\.dwg$"));
XElement filez = new XElement("filez");
foreach (String f in xfiles)
{
var yfiles = new My.Computer().FileSystem.GetFiles(dPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, string.Format("{0}*.dwg",System.IO.Path.GetFileNameWithoutExtension(f))).Where(c => Regex.IsMatch(c, #"_\d+\.dwg$"));
if (yfiles.Count() > 0)
{
filez.Add(new XElement("file", yfiles.Last()));
}
else {
filez.Add(new XElement("file", f));
};
};
Console.Write(filez);
Can you do this by string sort? The only tricky part I see here is to convert the file name to a sortable format. Just do a string replace from dd-mm-yyyy to yyyymmdd. Then, sort the the list and get the last record out.
This is what you want considering fileList contain all file names
List<string> latestFiles=new List<string>();
foreach(var groups in fileList.GroupBy(x=>Regex.Replace(x,#"(_\d+\.dwg$|\.dwg$)","")))
{
latestFiles.Add(groups.OrderBy(s=>Regex.Match(s,#"\d+(?=\.dwg$)").Value==""?0:int.Parse(Regex.Match(s,#"\d+(?=\.dwg$)").Value)).Last());
}
latestFiles has the list of all new files..
If fileList is bigger,use Threading or PLinq

Categories

Resources