I am using the below code to access the files in a certain path:
Dim dirInfo As New DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory & "/images/JobImages/" & projectname & "/" & ImageFolder & "/")
Dim allFiles As IO.FileInfo() = dirInfo.GetFiles("lightbox*.png")
This is bringing back the following files in the following order:
- Lightbox 4 - Lightbox3 - Lightbox2 - Lightbox1
My question is, is there a way to sort it so it returns the other way round? So as: -Lightbox1 - Lightbox2 - Lightbox3 - Lightbox4
You can use the Linq .OrderBy() method to sort the results, your problem will be that the sort will be done using a string comparison.
To fix this you would need to first extract just the number part of the filename then use this results of this to do the sorting.
void Main()
{
var files = new[]
{
"Lightbox1.png",
"Lightbox2.png",
"Lightbox10.png",
"Lightbox4.png",
"Lightbox3.png",
"Lightbox11.png",
"Lightbox7.png",
};
foreach (var f in files.OrderBy(x=>getFileNumber(x)))
Console.WriteLine(f);
}
int getFileNumber(string filename)
{
var n = new String(filename.Where(x=>char.IsNumber(x)).ToArray());
if (int.TryParse(n, out int i))
return i;
// parse failed
return -1;
}
Related
i am developing application in which i want that if user create folder and if it is already present then folder should automatically renamed by appending number to folder name
suppose server has folder with name Time now if user again creates folder than it new folder will be Time1 again user creates folder with same name(Time or Time1) than new Folder should be created with Time2 and so on... This is what i have done so far but recursion always return wrong value.
public string checkIfExist(String path, String ProgramName, int itteration,out string strFolderName)
{
String uploadPath = "";
strFolderName = "";
String Mappath =HttpContext.Current.Server.MapPath(path);
if (Directory.Exists(Mappath))
{
String Path = HttpContext.Current.Server.MapPath((path + "" + ProgramName.Replace(" ", "_")));
// uploadPath += ++itteration ;
if (Directory.Exists(Path))
{
ProgramName += ++itteration;
strFolderName = ProgramName;
uploadPath = checkIfExist(path, ProgramName, itteration,out strFolderName);
}
}
return ProgramName;
}
Perhaps you could adapt this, to your need. I wrote it on the fly based on a piece of code I remember in an old file manager I was using in some projects, so please test it. This doesn't include creation and so on, based on your example I'm sure you can add that yourself but if you need help just comment below.
The idea is to pass the original name of the directory you want, and then return an appropriate new name if it exists, such as Test(1), Test(2), Test(n). Then once you get the name you need, you can create it directly.
protected string GetUniqueDirectoryName(string dirName)
{
string newDirName = dirName;
for (int i = 1; Directory.Exists(Server.MapPath("PATH_HERE") + newDirName); i++)
{
newDirName = string.Format("{0}({1})", dirName, i);
}
return newDirName;
}
Note: You will need to include System.IO and probably use HttpContext.Current.Server.MapPath instead of Server.MapPath
I don't know if I really understand what you are trying to do, but I think using recursion here is a little overkill. Try something like this:
string dirName = "Time";
int counter = 0;
string dir = dirName;
while(Directory.Exists(dir))
{
dir = String.Format("{0}{1}", dirName, (++counter).ToString());
}
Directory.CreateDirectory(dir);
I'm retrieving a string array of files and I would like to custom sort them by a substring in the file name...using C# **.NET 3.5. Below is what I am working with.
<% string[] files = System.IO.Directory.GetFiles("...path..." + pageName + "\\reference\\");
files = String.Join(",", files).Replace("...path...", "").Replace("\\reference\\", "").Replace(pageName, "").Split(new Char[] { ',' });
foreach (String item in files)
{
Response.Write("<a href=" + pageName + "/reference/" + System.IO.Path.GetFileName(item) + " target='_blank'>" + item.Replace("_", " ").Replace(".pdf", " ") + "</a>");
}
%>
I'm a C# noob, and I don't know where to go from here. Basically, I'm looking for a substring in the file name to determine the order (e.g., "index","reference","list"; where any file including the string "index" would be listed first). Perhaps there is a better way to do it. Any help would be appreciated.
You can use Linq to order the array by the filenames. In general, use the Path class if you're working with paths.
string fullPath = Path.Combine(directory, pageName, "reference");
var filePaths = Directory.EnumerateFiles(fullPath, "*.*", SearchOption.TopDirectoryOnly)
.Select(fp => new{ FullPath = fp, FileName=Path.GetFileName(fp) })
.OrderByDescending(x => x.FileName.IndexOf("index", StringComparison.OrdinalIgnoreCase) >= 0)
.ThenByDescending(x => x.FileName.IndexOf("reference", StringComparison.OrdinalIgnoreCase) >= 0)
.ThenByDescending(x => x.FileName.IndexOf("list", StringComparison.OrdinalIgnoreCase) >= 0)
.ThenBy(x=> x.FileName)
.Select(x => x.FullPath);
foreach(string filePath in filePaths)
;// ...
If you don't want to compare case-insensitively (so that "index" and "Index" are considered the same) use String.Contains instead of String.IndexOf + StringComparison.OrdinalIgnoreCase.
Here's an easy way I use when I run into this problem.
Define the order of the substrings in a list. Then for each item, check to see whats the first thing that contains that item. Then sort by the order of the substring in the list.
public class SubStringSorter : IComparer<string>
{
public int Compare(string x, string y)
{
var source = x.ToLowerInvariant();
var target = y.ToLowerInvariant();
var types = new List<string> { "base", "data", "model", "services", "interceptor", "controllers", "directives", "filters", "app", "tests", "unittests" };
var sourceType = types.IndexOf(types.FirstOrDefault(source.Contains));
var targetType = types.IndexOf(types.FirstOrDefault(target.Contains));
return sourceType.CompareTo(targetType);
}
}
To sort your files, do something like
var list = new List<string>{ "baseFile", "servicesFile", "this ModElstuff" };
list.Sort(new SubStringSorter());
And the output
You could even go one step further and give the substring sorter the list as part of its constructor so you can re-use the substring sort order with other items. The example I posted tests if the string exists in any context, but if you are more interested in it starting with a string you can do that too.
I use Epplus to reading xlsx files from stream.
It has a bug , it cant read some columns in my workbook.How can read xlsx files from stream to datatable without epplus ?
my older code:
public static DataSet ReadExcelFile(Stream stream)
{
try
{
//2. Reading from a OpenXml Excel file (2007 format; *.xlsx)
IExcelDataReader excelReader =
ExcelReaderFactory.CreateOpenXmlReader(stream);
//...
DataSet result = excelReader.AsDataSet();
return result;
}
catch (Exception x)
{
throw x;
}
}
I didnt report it, but i tried so much combinations.If there are empty columns in worksheet ,epplus reader cant read correctly column values.
"It has a bug , it cant read some columns in my workbook"
Can you describe the bug, have you reported it or is it already known, what version are you using?
Here's a simple approach to load an excel file into a DataTable with EPPlus.
public static DataTable getDataTableFromExcel(string path)
{
using (var pck = new OfficeOpenXml.ExcelPackage())
{
using (var stream = File.OpenRead(path))
{
pck.Load(stream);
}
var ws = pck.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
bool hasHeader = true; // adjust it accordingly( i've mentioned that this is a simple approach)
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
{
tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
}
var startRow = hasHeader ? 2 : 1;
for (var rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
var row = tbl.NewRow();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
tbl.Rows.Add(row);
}
return tbl;
}
}
This is way past, however it could still help someone.
Apparently some columns in my worksheet were merged, so for example, if columns A and B are merged it only recognizes column A as the one with the value, and so it returns column B as empty, when i call on that particular cell's value(B). To get past this, make sure you know which cells are merged and then grab only the first one and regard the rest of the merged cells as null
I've had several cases where I had a page with several query parameters - most recently a search results page - and needed to create a link to the same page with one or more query parameters changed in the URL. This seems like such a common use case that I feel as though there must be some simple built-in way of doing it.
Right now, I'm using a function I wrote which takes in a dictionary of parameters and values and merges them with the params and values from Request.QueryString. Parameters given with a null value are removed. It works, but I'm open to simpler methods.
Minor improvements I'd suggest:
//...
{
UriBuilder ub = new UriBuilder(Request.Url);
//...
ub.Query = string.Join("&", parameters.Select(kv => string.Format("{0}={1}", Server.UrlEncode(kv.Key), Server.UrlEncode(kv.Value))));
return ub.ToString();
}
Edit
Actually the return value should also be a Uri type but I didn't want to introduce any breaking changes.
The function I'm using now:
public string ThisPageWithParams(IDictionary<string, string> newParameters)
{
string url = Request.Url.AbsolutePath + "?";
var parameters = new Dictionary<string, string>();
foreach (string k in Request.QueryString)
{
parameters[k] = Request.QueryString[k];
}
foreach (var kv in newParameters)
{
if (newParameters[kv.Key] == null)
{
parameters.Remove(kv.Key);
}
else
{
parameters[kv.Key] = kv.Value;
}
}
url += string.Join("&", parameters.Select(kv => Server.UrlEncode(kv.Key) + "=" + Server.UrlEncode(kv.Value)));
return url;
}
I've produced this code to read an xml file from a string, however it has problems. Notably the ReadToFollowing() method returns nothing. It seems to seek the whole xmlstring, then set the XMLReader state to the EndofFile. I'm very puzzled by this, ReadStartElement() works and the next element is read as "heading" as you'd expect.
Here's my code, my idea is to read through the xml pulling out the fields I require;
List<string> contentfields = new List<string>() { "heading", "shortblurb", "description" };
string xml = #"<filemeta filetype='Audio'><heading>Fatigue & Tiredness</heading><shortblurb>shortblurb</shortblurb><description /><Comments /><AlbumTitle /><TrackNumber /><ArtistName /><Year /><Genre /><TrackTitle /></filemeta>";
using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
{
reader.ReadStartElement("filemeta");
foreach (String field_str in contentfields)
{
reader.ReadToFollowing(field_str);
if (reader.Name.ToString() == field_str)
{
Console.WriteLine(field_str + " " + reader.ReadElementContentAsString());
}
}
}
Console.ReadKey();
That's because reader.ReadStartElement("filemeta"); will position the reader on the xml tag heading.
ReadToFollowing will then do 1 read (reading past your heading tag) and then start to seek an element with the name heading. As you just read past it, ReadToFollowing will not find it anymore and read to the end of the file.
If you want to avoid this, change your code like this :
List<string> contentfields = new List<string>() { "heading", "shortblurb", "description" };
string xml = #"<filemeta filetype='Audio'><heading>Fatigue & Tiredness</heading><shortblurb>shortblurb</shortblurb><description /><Comments /><AlbumTitle /><TrackNumber /><ArtistName /><Year /><Genre /><TrackTitle /></filemeta>";
using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
{
reader.ReadStartElement("filemeta");
foreach (String field_str in contentfields)
{
if (reader.Name.ToString() != field_str)
{
reader.ReadToFollowing(field_str);
}
//still keep this if because we could have reached the end of the xml document
if (reader.Name == field_str)
{
Console.WriteLine(field_str + " " + reader.ReadElementContentAsString());
}
}
}
Console.ReadKey();