I have to process files everyday. The files are named like so:
fg1a.mmddyyyy
fg1b.mmddyyyy
fg1c.mmddyyyy
fg2a.mmddyyyy
fg2b.mmddyyyy
fg2c.mmddyyyy
fg2d.mmddyyyy
If the entire file group is there for a particular date, I can process it. If it isn't there, I should not process it. I may have several partial file groups that run over several days. So when I have fg1a.12062017, fg1b.12062017 and fg1c.12062017, I can process that group (fg1) only.
Here is my code so far. It doesn't work because I can't figure out how to get only the full groups to add to the the processing file list.
fileList = Directory.GetFiles(#"c:\temp\");
string[] fileGroup1 = { "FG1A", "FG1B", "FG1C" }; // THIS IS A FULL GROUP
string[] fileGroup2 = { "FG2A", "FG2B", "FG2C", "FG2D" };
List<string> fileDates = new List<string>();
List<string> procFileList;
// get a list of file dates
foreach (string fn in fileList)
{
string dateString = fn.Substring(fn.IndexOf('.'), 9);
if (!fileDates.Contains(dateString))
{
fileDates.Add(dateString);
}
}
bool allFiles = true;
foreach (string fg in fileGroup1)
{
foreach (string fd in fileDates)
{
string finder = fg + fd;
bool foundIt = false;
foreach (string fn in fileList)
{
if (fn.ToUpper().Contains(finder))
{
foundIt = true;
}
}
if (!foundIt)
{
allFiles = false;
}
else
{
foreach (string fn in fileList)
{
procFileList.Add(fn);
}
}
}
}
foreach (string fg in fileGroup2)
{
foreach (string fd in fileDates)
{
string finder = fg + fd;
bool foundIt = false;
foreach (string fn in fileList)
{
if (fn.ToUpper().Contains(finder))
{
foundIt = true;
}
}
if (!foundIt)
{
allFiles = false;
}
else
{
foreach (string fn in fileList)
{
procFileList.Add(fn);
}
}
}
}
Any help or advice would be greatly appreciated.
Because it can sometimes get messy dealing with multiple lists, groupings, and parsing file names, I would start by creating a class that represents a FileGroupItem. This class would have a Parse method that takes in a file path, and then has properties that represent the group part and date part of the file name, as well as the full path to the file:
public class FileGroupItem
{
public string DatePart { get; set; }
public string GroupName { get; set; }
public string FilePath { get; set; }
public static FileGroupItem Parse(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath)) return null;
// Split the file name on the '.' character to get the group and date parts
var fileParts = Path.GetFileName(filePath).Split('.');
if (fileParts.Length != 2) return null;
return new FileGroupItem
{
GroupName = fileParts[0],
DatePart = fileParts[1],
FilePath = filePath
};
}
}
Then, in my main code, I would create a list of the file group definitions, and then populate a list of FileGroupItems from the directory we're scanning. After that, we can determine if any file group definition is complete by comparing it's items (in a case-insensitive way) to the actual FileGroupItems we found in the directory (after first grouping the FileGroupItems by it's DatePart). If the intersection of these two lists has the same number of items as the file group definition, then it's complete and we can process that group.
Maybe it will make more sense in code:
private static void Main()
{
var scanDirectory = #"f:\public\temp\";
var processedDirectory = #"f:\public\temp2\";
// The lists that define a complete group
var fileGroupDefinitions = new List<List<string>>
{
new List<string> {"FG1A", "FG1B", "FG1C"},
new List<string> {"FG2A", "FG2B", "FG2C", "FG2D"}
};
// Populate a list of FileGroupItems from the files
// in our directory, and group them on the DatePart
var fileGroups = Directory.EnumerateFiles(scanDirectory)
.Select(FileGroupItem.Parse)
.GroupBy(f => f.DatePart);
// Now go through each group and compare the items
// for that date with our file group definitions
foreach (var fileGroup in fileGroups)
{
foreach (var fileGroupDefinition in fileGroupDefinitions)
{
// Get the intersection of the group definition and this file group
var intersection = fileGroup
.Where(f => fileGroupDefinition.Contains(
f.GroupName, StringComparer.OrdinalIgnoreCase))
.ToList();
// If all the items in the definition are there, then process the files
if (intersection.Count == fileGroupDefinition.Count)
{
foreach (var fileGroupItem in intersection)
{
Console.WriteLine($"Processing file: {fileGroupItem.FilePath}");
// Move the file to the processed directory
File.Move(fileGroupItem.FilePath,
Path.Combine(processedDirectory,
Path.GetFileName(fileGroupItem.FilePath)));
}
}
}
}
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
I think you could simplify your algorithm so you just have file groups as a prefix and a number of files to expect, fg1 is 3 files for a given date
I think your code to find the distinct dates present is a good idea, though you should use a hash set rather than a list, if you occasionally expect a large number of dates.. ("Valentine's Day?" - Ed)
Then you just need to work on the other loop that does the checking. An algorithm like this
//make a new Dictionary<string,int> for the filegroup prefixes and their counts3
//eg myDict["fg1"] = 3; myDict["fg2"] = 4;
//list the files in the directory, into an array of fileinfo objects
//see the DirectoryInfo.GetFiles method
//foreach string d in the list of dates
//foreach string fgKey in myDict.Keys - the list of group prefixes
//use a bit of Linq to get all the fileinfos with a
//name starting with the group and ending with the date
var grplist = myfileinfos.Where(fi => fi.Name.StartsWith(fg) && fi.Name.EndsWith(d));
//if the grplist.Count == the filegroup count ( myDict[fgKey] )
//then send every file in grplist for processing
//remember that grplist is a collection of fileinfo objects,
//if your processing method takes a string filename, use fileinfo.Fullname
Putting your file groupings into one dictionary will make things a lot easier than having them as x separate arrays
I haven't written all the code for you, but I've comment sketched the algorithm, and I've put in some of the more awkward bits like the link, dictionary declaration and how to fill it.. have a go at fleshing it out with code, ask any questions in a comment on this post
First, create an array of the groups to make processing easier:
var fileGroups = new[] {
new[] { "FG1A", "FG1B", "FG1C" },
new[] { "FG2A", "FG2B", "FG2C", "FG2D" }
};
Then you can convert the array into a Dictionary to map each name back to its group:
var fileGroupMap = fileGroups.SelectMany(g => g.Select(f => new { key = f, group = g })).ToDictionary(g => g.key, g => g.group);
Then, preprocess the files you get from the directory:
var fileList = from fname in Directory.GetFiles(...)
select new {
fname,
fdate = Path.GetExtension(fname),
ffilename = Path.GetFileNameWithoutExtension(fname).ToUpper()
};
Now you can take your fileList and group by date and group, and then filter to just completed groups:
var profFileList = (from file in fileList
group file by new { file.fdate, fgroup = fileGroupMap[file.ffilename] } into fng
where fng.Key.fgroup.All(f => fng.Select(fn => fn.ffilename).Contains(f))
from fn in fng
select fn.fname).ToList();
Since you didn't preserve the groups, I flattened the groups at the end of the query into just a list of files to be processed. If you needed, you could keep them in groups and process the groups instead.
Note: If a file exists that belongs to no group, you will get an error from the lookup in fileGroupMap. If that is a possiblity you can filter the fileList to just known names as follows:
var fileList = from fname in GetFiles
let ffilename = Path.GetFileNameWithoutExtension(fname).ToUpper()
where fileGroupMap.Keys.Contains(ffilename)
select new {
fname,
fdate = Path.GetExtension(fname),
ffilename
};
Also note that having a name in multiple groups will cause an error in the creation of fileGroupMap. If that is a possibility, the queries would become more complex and have to be written differently.
Here is a simple class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string[] filenames = { "fg1a.12012017", "fg1b.12012017", "fg1c.12012017", "fg2a.12012017", "fg2b.12012017", "fg2c.12012017", "fg2d.12012017" };
new SplitFileName(filenames);
List<List<SplitFileName>> results = SplitFileName.GetGroups();
}
}
public class SplitFileName
{
public static List<SplitFileName> names = new List<SplitFileName>();
string filename { get; set; }
string prefix { get; set; }
string letter { get; set; }
DateTime date { get; set; }
public SplitFileName() { }
public SplitFileName(string[] splitNames)
{
foreach(string name in splitNames)
{
SplitFileName splitName = new SplitFileName();
names.Add(splitName);
splitName.filename = name;
string[] splitArray = name.Split(new char[] { '.' });
splitName.date = DateTime.ParseExact(splitArray[1],"MMddyyyy", System.Globalization.CultureInfo.InvariantCulture);
splitName.prefix = splitArray[0].Substring(0, splitArray[0].Length - 1);
splitName.letter = splitArray[0].Substring(splitArray[0].Length - 1,1);
}
}
public static List<List<SplitFileName>> GetGroups()
{
return names.OrderBy(x => x.letter).GroupBy(x => new { date = x.date, prefix = x.prefix })
.Where(x => string.Join(",",x.Select(y => y.letter)) == "a,b,c,d")
.Select(x => x.ToList())
.ToList();
}
}
}
With everyone's help, I solved it too. This is what I'm going with because it's the most maintainable for me but the solutions were so smart!!! Thanks everyone for your help.
private void CheckFiles()
{
var fileGroups = new[] {
new [] { "FG1A", "FG1B", "FG1C", "FG1D" },
new[] { "FG2A", "FG2B", "FG2C", "FG2D", "FG2E" } };
List<string> fileDates = new List<string>();
List<string> pfiles = new List<string>();
// get a list of file dates
foreach (string fn in fileList)
{
string dateString = fn.Substring(fn.IndexOf('.'), 9);
if (!fileDates.Contains(dateString))
{
fileDates.Add(dateString);
}
}
// check if a date has all the files
foreach (string fd in fileDates)
{
int fgCount = 0;
// for each file group
foreach (Array masterfg in fileGroups)
{
foreach (string fg in masterfg)
{
// see if all the files are there
bool foundIt = false;
string finder = fg + fd;
foreach (string fn in fileList)
{
if (fn.ToUpper().Contains(finder))
{
pfiles.Add(fn);
}
}
fgCount++;
}
if (fgCount == pfiles.Count())
{
foreach (string fn in pfiles)
{
procFileList.Add(fn);
}
pfiles.Clear();
}
else
{
pfiles.Clear();
}
}
}
return;
}
Related
Have the problem with regexp on C#. I get the list of strings (names of directory) by Directory.GetDirectories.
For example:
E:\DevArea\SandBox\1122334455
E:\DevArea\SandBox\1231231231
E:\DevArea\SandBox\1231231232
E:\DevArea\SandBox\1231231233
E:\DevArea\SandBox\1231231234
E:\DevArea\SandBox\123123123123
E:\DevArea\SandBox\1231231231ddd
I need to find directories names witch consists of only 10 digits (only 10).
I tried to use next:
public List<string> GetDirectoryList()
{
var directoryList = new List<string>();
var list = Directory.GetDirectories(sourcePath);
foreach (var field in list)
{
if (checker.CheckInfo(field.Substring(field.LastIndexOf('\\') + 1)))
{
directoryList.Add(field);
}
}
return directoryList;
}
public bool CheckInfo(string checkingInfo)
{
string stringPattern = "[0-9]{10}";
if (!Regex.IsMatch(checkingInfo, stringPattern))
{
return false;
}
return true;
}
As result i had list of directories names witch consist of digits, but there were the next one:
E:\DevArea\SandBox\123123123123
How can i ignore names with more than 10 digit?
It is better to do this in my case, i think:
public List<string> GetDirectoryList()
{
var directoryList = new List<string>();
var list = Directory.GetDirectories(sourcePath);
string stringPattern = "(?<!\d)[0-9]{10}(?!\d)";
foreach (var field in list)
{
if (Regex.IsMatch(checkingInfo, stringPattern))
{
directoryList.Add(field);
}
}
return directoryList;
}
Thanks for ctwheels!
Just do it:
public bool CheckInfo(string checkingInfo)
{
return Regex.IsMatch(checkingInfo, "^[0-9]{10}$");
}
private void btnOpen_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == DialogResult.OK)
{
listBox1.Items.Clear();
string[] allfiles = Directory.GetFiles(fbd.SelectedPath, "*.txt*",
SearchOption.AllDirectories);
foreach (string file in allfiles)
{
FileInfo info = new FileInfo(file);
listBox1.Items.Add(Path.GetFileName(file));
}
}
}
There is listbox1 with all .txt files from direcory and subfolder...
Now I need from this listBox all files and search by some string.
Can I iterate loop and read file by file?
I don't have an idea how read and search files, need I open first, then store a data of file somewhere, maybe list or listView?
First, I would use a class of its own to store your search results. When we search files, and if we find the keyword we're searching for, we'd create an object of this class and at it to a list. Something like this:
public class SearchResults
{
public string FilePath { get; set; }
public string SearchWord { get; set; }
public int Occurences { get; set; }
}
Then you can use the System.IO.File class to read your files. Remember this is not the only way, but merely one way of doing it. Here I have a list of file names, which is equivalent to the array you have in your program.
var searchTerm = "Hello";
var fileList = new List<string>() { "A.txt", "B.txt", "C.txt" };
var resultList = new List<SearchResults>();
// Iterate through files. You already are doing this.
foreach (var file in fileList)
{
// Check to see if file exists. This is a second line of defense in error checking, not really necessary but good to have.
if (File.Exists(file))
{
// Read all lines in the file into an array of strings.
var lines = File.ReadAllLines(file);
// In this file, extract the lines contain the keyword
var foundLines = lines.Where(x => x.Contains(searchTerm));
if (foundLines.Count() > 0)
{
var count = 0;
// Iterate each line that contains the keyword at least once to see how many times the word appear in each line
foreach (var line in foundLines)
{
// The CountSubstring helper method counts the number of occurrences of a string in a string.
var occurences = CountSubstring(line, searchTerm);
count += occurences;
}
// Add the result to the result list.
resultList.Add(new SearchResults() { FilePath = file, Occurences = count, SearchWord = searchTerm });
}
}
}
The CountSubstring() helper method.
public static int CountSubstring(string text, string value)
{
int count = 0, minIndex = text.IndexOf(value, 0);
while (minIndex != -1)
{
minIndex = text.IndexOf(value, minIndex + value.Length);
count++;
}
return count;
}
so I have some strings in a list
Folder1\File.png
Folder1\File2.png
File3.png
File4.png
and I would like to group these on a split('\\')[0]; for example
foreach (var group in files.GroupBy(x => //mysplit))
{
if (group.Count() > 1)
{
// this is a folder and its files are: group
}
else
{
//group is an individual file
}
}
but I'm not sure how to group the files by this split?
I would just group items that Contains() a backslash:
var lst1 = new string[] {"Folder1\\File.png", "Folder1\\File2.png" , "File3.png", "File4.png" };
var grps = lst1.GroupBy(x => x.Contains(#"\"));
foreach (var g in grps)
{
if (g.Key) // we have a path with directory
Console.WriteLine(String.Join("\r\n", g.ToList()));
else // we have an individual file
Console.WriteLine(String.Join("\r\n", g.ToList()));
}
So my solution was:
foreach (var groupedFiles in files.GroupBy(s => s.Split('\\')[0]))
{
if (Path.GetExtension(groupedFiles.Key) == string.Empty)
{
//this is a folder
var folder = groupedFiles.Key;
var folderFiles = groupedFiles.ToList();
}
else
{
//this is a file
var file = groupedFiles.First();
}
}
Firstly, I'm new to C# and I'm having a hard time figuring out how I'd go about doing this.
Basically, I have multiple text files all with their own types of data. My aim is to read the first line of each of these files and combine them into one string so that I can sort them later by their respective days.
For example, in the first line of each file there could be the values...
File 1: 16/02/15
File 2: Monday
File 3: 75.730
File 4: 0.470
File 5: 75.260
File 6: 68182943
So I'd like to combine them in a string like so "16/02/15 Monday 75.730 0.470 75.260 68182943"
I'd also want to do this for the second, third, fourth line etc. There are a total of 144 entries or lines.
Here is the code I have so far. I'm unsure if I'm on the right track.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace BankAlgorithms
{
class Algorithms
{
static void Main(string[] args)
{
//Saves each individual text file into their own string arrays.
string[] Day = File.ReadAllLines(#"C:\Users\computing\Desktop\algorithms\CMP1124M_Assigment_Files\Day.txt");
string[] Date = File.ReadAllLines(#"C:\Users\computing\Desktop\algorithms\CMP1124M_Assigment_Files\Date.txt");
string[] Close = File.ReadAllLines(#"C:\Users\computing\Desktop\algorithms\CMP1124M_Assigment_Files\SH1_Close.txt");
string[] Diff = File.ReadAllLines(#"C:\Users\computing\Desktop\algorithms\CMP1124M_Assigment_Files\SH1_Diff.txt");
string[] Open = File.ReadAllLines(#"C:\Users\computing\Desktop\algorithms\CMP1124M_Assigment_Files\SH1_Open.txt");
string[] Volume = File.ReadAllLines(#"C:\Users\computing\Desktop\algorithms\CMP1124M_Assigment_Files\SH1_Volume.txt");
//Lists all files currently stored within the directory
string[] bankFiles = Directory.GetFiles(#"C:\Users\computing\Desktop\algorithms\CMP1124M_Assigment_Files");
Console.WriteLine("Bank Files currently saved within directory:\n");
foreach (string name in bankFiles)
{
Console.WriteLine(name);
}
Console.WriteLine("\nSelect the day you wish to view the data of (Monday-Friday). To view a grouped \nlist of all days, enter \"Day\"\n");
string selectedArray = Console.ReadLine();
if (selectedArray == "Day")
{
Console.WriteLine("Opening Day File...");
Console.WriteLine("\nDays grouped up in alphabetical order\n");
var sort = from s in Day
orderby s
select s;
foreach (string c in sort)
{
Console.WriteLine(c);
}
}
Console.ReadLine();
}
}
}
So this might be a little more than you strictly need, but I think it'll be robust, quite flexible and be able to handle huge files if need be.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ConsoleApplication2
{
class Program
{
private static void Main(string[] args)
{
// const string folder = #"C:\Users\computing\Desktop\algorithms\CMP1124M_Assigment_Files";
const string folder = #"C:\Temp\SO";
var filenames = new[] { #"Date.txt", #"Day.txt", #"SH1_Close.txt", #"SH1_Diff.txt", #"SH1_Open.txt", #"SH1_Volume.txt" };
var dataCombiner = new DataCombiner(folder, filenames);
var stockParser = new StockParser();
foreach (var stock in dataCombiner.GetCombinedData(stockParser.Parse)) //can also use where clause here
{
if (ShowRow(stock))
{
var outputText = stock.ToString();
Console.WriteLine(outputText);
}
}
Console.ReadLine();
}
private static bool ShowRow(Stock stock)
{
//use input from user etc...
return (stock.DayOfWeek == "Tuesday" || stock.DayOfWeek == "Monday")
&& stock.Volume > 1000
&& stock.Diff < 10; // etc
}
}
internal class DataCombiner
{
private readonly string _folder;
private readonly string[] _filenames;
public DataCombiner(string folder, string[] filenames)
{
_folder = folder;
_filenames = filenames;
}
private static IEnumerable<string> GetFilePaths(string folder, params string[] filenames)
{
return filenames.Select(filename => Path.Combine(folder, filename));
}
public IEnumerable<T> GetCombinedData<T>(Func<string[], T> parserMethod) where T : class
{
var filePaths = GetFilePaths(_folder, _filenames).ToArray();
var files = filePaths.Select(filePath => new StreamReader(filePath)).ToList();
var lineCounterFile = new StreamReader(filePaths.First());
while (lineCounterFile.ReadLine() != null)// This can be replaced with a simple for loop if the files will always have a fixed number of rows
{
var rawData = files.Select(file => file.ReadLine()).ToArray();
yield return parserMethod(rawData);
}
}
}
internal class Stock
{
public DateTime Date { get; set; }
public string DayOfWeek { get; set; }
public double Open { get; set; }
public double Close { get; set; }
public double Diff { get; set; }
public int Volume { get; set; }
public override string ToString()
{
//Whatever format you want
return string.Format("{0:d} {1} {2} {3} {4} {5}", Date, DayOfWeek, Close, Diff, Open, Volume);
}
}
internal class StockParser
{
public Stock Parse(string[] rawData)
{
//TODO: Error handling required here
var stock = new Stock();
stock.Date = DateTime.Parse(rawData[0]);
stock.DayOfWeek = rawData[1];
stock.Close = double.Parse(rawData[2]);
stock.Diff = double.Parse(rawData[3]);
stock.Open = double.Parse(rawData[4]);
stock.Volume = int.Parse(rawData[5]);
return stock;
}
public string ParseToRawText(string[] rawData)
{
return string.Join(" ", rawData);
}
}
}
PS:
Instead of reading it from the file, I'd rather also calculate the DayOfWeek from the Date.
Also be careful when parsing dates from a different locale (eg. USA vs UK).
If you have an option I'd only use the ISO 8601 datetime format.
Access your file strings from a collection, use this code to read from each file and use a StringBuilder to build your string.
Read only the first few lines of text from a file
var builder = new StringBuilder();
foreach(var file in fileList)
{
using (StreamReader reader = new StreamReader(file))
{
builder.Append(reader.ReadLine());
}
}
return builder.ToString();
You could use following approach: put all in an string[][] first, then it's easier:
string[][] all = { Day, Date, Close, Diff, Open, Volume };
To get the minimum length of all:
int commonRange = all.Min(arr => arr.Length);
Now this is all you need:
string[] merged = Enumerable.Range(0, commonRange)
.Select(i => string.Join(" ", all.Select(arr => arr[i])))
.ToArray();
This is similar to a for-loop from 0 to commonRange where you access all arrays with the same index and use String.Join to get a single string from all files' lines.
Since you have commented that you want to merge only the lines of a specific day:
var lineIndexes = Day.Take(commonRange)
.Select((line, index) => new { line, index })
.Where(x => x.line.TrimStart().StartsWith("Monday", StringComparison.InvariantCultureIgnoreCase))
.Select(x => x.index);
string[] merged = lineIndexes
.Select(i => string.Join(" ", all.Select(arr => arr[i])))
.ToArray();
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have little to no knowledge with C#. That being said, I have been tasked with a project of sorting a list based on the latest version of jQuery in a folder where a bunch of versions are held.
Currently, this is what I have:
public ActionResult Index()
{
//creating a DirectoryInfo object
DirectoryInfo mydir = new DirectoryInfo(#"\\edcapptest\E$\cdn\js\jquery");
// getting the files in the directory
FileInfo[] f = mydir.GetFiles();
List<string> myList = new List<string>();
foreach (FileInfo file in f)
{
myList.Add(file.Name);
}
myList.Sort();
return View(myList);
}
I have been thinking about ways I can go about doing this for a few days now, and have come up with little to no results(at least ones that work).
Any suggestions or help will be greatly appreciated.
Assuming an alphabetical ordering will put it in the right order... your code to get the ordered list could look like this....
I'm using LINQ method syntax and comment each line since you mentioned you don't know a lot about C#.
public ActionResult Index()
{
//creating a DirectoryInfo object
DirectoryInfo mydir = new DirectoryInfo(#"\\edcapptest\E$\cdn\js\jquery");
// getting the files in the directory
var myList = mydir.GetFiles() // Your objects in the list you start with
// Filter for the jquery files... you may not need this line
.Where(file => file.Name.StartsWith("jquery-"))
// Select the filename and version number so we can sort
.Select(file => new { Name= file.Name, Version = GetVersion(file.Name)})
// OrderBy the version number
.OrderBy(f => f.Version)
// We have to select just the filename since that's all you want
.Select(f => f.Name)
// Convert your output into a List
.ToList();
return View(myList);
}
// GetVersion code and regex to remove characters...
private static Regex digitsOnly = new Regex(#"[^\d]");
public static Version GetVersion(string filename)
{
var versionNumbers = new List<int>();
var splits = filename.Split('.');
foreach (var split in splits)
{
var digits = digitsOnly.Replace(filename, "");
if (!string.IsNullOrEmpty(digits))
versionNumbers.Add(int.Parse(digits));
}
// Create a version which can have various major / minor versions and
// handles sorting for you.
return new Version(versionNumbers[0], versionNumbers[1],
versionNumbers[2]);
}
not intended to be a complete solution but this should get you close.
public List<jquery> GetVersion(string path)
{
var thelist = (from afile in System.IO.Directory.EnumerateFiles(path)
let version = removeLetters(afile)
select removeLetters(afile).Split('.')
into splitup
select new jquery()
{
Filename = filename,
//will want to add some additional checking here as if the length is not 3 then there will be other errors.
//just a starting point for you
Major = string.IsNullOrWhiteSpace(splitup[0]) ? 0 : int.Parse(splitup[0]),
Minor = string.IsNullOrWhiteSpace(splitup[1]) ? 0 : int.Parse(splitup[1]),
Build = string.IsNullOrWhiteSpace(splitup[2]) ? 0 : int.Parse(splitup[2]),
}).ToList();
return thelist
.OrderByDescending(f => f.Major)
.ThenByDescending(f => f.Minor)
.ThenByDescending(f => f.Build)
.ToList();
}
public string removeLetters(string value)
{
var chars = value.ToCharArray().Where(c => Char.IsNumber(c) || c.Equals('.'));
return chars.ToString();
}
public class jquery
{
public string Filename { get; set; }
public int Major { get; set; }
public int Minor { get; set; }
public int Build { get; set; }
}
I have created a class to do all the work for me, but you don't have to do that, I just find it easier. I use a regex to pull the version number out of the file name, then split that into the 3 integer parts of the version number.
public class JQueryVersion
{
public string File_Name { get; set; }
public string Version
{
get
{
return Regex.Match(this.File_Name, #"jquery-([0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2})\.").Groups[1].Value;
}
}
public int[] Version_Numeric
{
get
{
return this.Version.Split('.').Select(v => int.Parse(v)).ToArray();
}
}
public JQueryVersion (string File_Name)
{
this.File_Name = File_Name;
}
}
You can then create and sort the list of JQueryVersion objects like this:
List<JQueryVersion> Data = new List<JQueryVersion>()
{
new JQueryVersion("jquery-1.10.2.min.js"),
new JQueryVersion("jquery-1.11.0.min.js"),
new JQueryVersion("jquery-1.5.1.min.js"),
new JQueryVersion("jquery-1.6.1.min.js"),
new JQueryVersion("jquery-1.6.2.min.js"),
};
var Sorted_Data = Data
.OrderByDescending (d => d.Version_Numeric[0])
.ThenByDescending (d => d.Version_Numeric[1])
.ThenByDescending (d => d.Version_Numeric[2]);
I personnaly use Sort(Comparison< T >) for homemade comparisons :
http://msdn.microsoft.com/en-us/library/w56d4y5z%28v=vs.110%29.aspx
Here is an example comparing your files modification dates :
public ActionResult Index()
{
//creating a DirectoryInfo object
DirectoryInfo mydir = new DirectoryInfo(#"\\edcapptest\E$\cdn\js\jquery");
// getting the files in the directory
FileInfo[] f = mydir.GetFiles();
List<string> myList = new List<string>();
foreach (FileInfo file in f)
{
myList.Add(file.Name);
}
myList.Sort(SortByModificationDate);
return View(myList);
}
public int SortByModificationDate(string file1, string file2)
{
DateTime time1 = File.GetLastWriteTime(file1);
DateTime time2 = File.GetLastWriteTime(file2);
return time1.CompareTo(time2);
}