C# Index out of range - Array without content - c#

Hello Stackoverflow people!
I'm making a school project and currently got the whole program working, but I want to make it fail proof, but I'm having trouble that an array goes out of range if I just press ENTER instead of putting any info in.
string[] strIpAddress = ipAndSubnetArray[0].Split('.');
string[] strSubnetMask = new string[] { "" };
int[] intSubnetMask = new int[] { };
string strCIDR = "";
string cidrSubnetmask = "";
if (ipAndSubnetArray[1].Length > 2)
{
strSubnetMask = ipAndSubnetArray[1].Split('.');
intSubnetMask = strArray2IntArray(strSubnetMask);
}
else if (ipAndSubnetArray[1].Length < 3)
{
strCIDR = Convert.ToString(ipAndSubnetArray[1]);
cidrSubnetmask = cidrTilDeci(Convert.ToInt32(strCIDR));
strSubnetMask = cidrSubnetmask.Split('.');
intSubnetMask = strArray2IntArray(strSubnetMask);
}
else if (ipAndSubnetArray == null)
{
Main();
}
I tried fixing with with ipAndSubnetArray == null but that didn't seem to do the trick. Any suggestions? If you need more of the code let me know.

I'm assuming data comes in from a terminal or other input when you press enter and is passed in via ipAndSubnetArray. ipAndSubnetArray is apparently null when this happens. Your check for this is at the end, move it to the top to prevent accessing any indexes that aren't there.
The ipAndSubnetArray.Length >= 2 check is to guarantee you can access ipAndSubnetArray[1]. You could also do this inside like so if (ipAndSubnetArray.Length > 1 && ipAndSubnetArray[1].Length > 2).
if(ipAndSubnetArray != null && ipAndSubnetArray.Length >= 2) {
string[] strIpAddress = ipAndSubnetArray[0].Split('.');
string[] strSubnetMask = new string[] { "" };
int[] intSubnetMask = new int[] { };
string strCIDR = "";
string cidrSubnetmask = "";
if (ipAndSubnetArray[1].Length > 2)
{
strSubnetMask = ipAndSubnetArray[1].Split('.');
intSubnetMask = strArray2IntArray(strSubnetMask);
}
else if (ipAndSubnetArray[1].Length < 3)
{
strCIDR = Convert.ToString(ipAndSubnetArray[1]);
cidrSubnetmask = cidrTilDeci(Convert.ToInt32(strCIDR));
strSubnetMask = cidrSubnetmask.Split('.');
intSubnetMask = strArray2IntArray(strSubnetMask);
}
} else {
Main()
}

Related

c# datatable "index was outside the bounds of the array" [duplicate]

Im using the following code to split up a string and store it:
string[] proxyAdrs = linesProxy[i].Split(':');
string proxyServer = proxyAdrs[0];
int proxyPort = Convert.ToInt32(proxyAdrs[1]);
if(proxyAdrs[2] != null)
{
item.Username = proxyAdrs[2];
}
if (proxyAdrs[3] != null)
{
item.Password = proxyAdrs[3];
}
The problem is i am getting
Index was outside the bounds of the array.
When proxyAdrs[2] is not there.
Sometimes proxyAdrs[2] will be there sometimes not.
How can i solve this?
Just check the length of the array returned in your if statement
if( proxyAdrs.Length > 2 && proxyAdrs[2] != null)
{
item.Username = proxyAdrs[2];
}
The reason you are getting the exception is that the split is returning array of size less than the index you are accessing with. If you are accessing the array element 2 then there must be atleast 3 elements in the array as array index starts with 0
You can check the length of array before accessing its element by index.
Change
if(proxyAdrs[2] != null)
{
item.Username = proxyAdrs[2];
}
To
if(proxyAdrs.Length > 2 )
{
item.Username = proxyAdrs[2];
}
Try this:
string[] proxyAdrs = linesProxy[i].Split(':');
string proxyServer = proxyAdrs[0];
int proxyPort = Convert.ToInt32(proxyAdrs[1]);
if(proxyAdrs.Length > 2 && proxyAdrs[2] != null)
{
item.Username = proxyAdrs[2];
}
if (proxyAdrs.Length > 3 && proxyAdrs[3] != null)
{
item.Password = proxyAdrs[3];
}
Check the length of proxyAdrs before you attempt to subscript a potentially non-existent item.
if ( proxyAdrs.Length > 1 ) {
item.Username = proxyAdrs[2];
}
It is that your i which might be lower than the 2 you are trying to set in as index :)
if i >= 2 then you can do all of the follwing:----
if(proxyAdrs[2] != null)
{
item.Username = proxyAdrs[2];
}
if (proxyAdrs[3] != null)
{
item.Password = proxyAdrs[3];
}
}
else I suggest you get out :D
But again, checking proxyAdrs.Lenght would be the best.
There are two options that may help you, depending of whether or not you form incoming data (variable linesProxy):
If you do form incoming data: Always include all parts of the string. In your case, always ensure you have 4 (assuming proxyAdrs[3] is the last) parts by adding additional : between 1st and 3rd values if no value for 2nd is provided. Thus after .Split() operation (ensure you don't activate RemoveEmptyStrings option ) your proxyAdrs[2] will be null and your sample will be fine.
Otherwise: if proxyAdrs[2] is the only part the can be empty following snippet can prevent crashing:
string[] proxyAdrs = linesProxy[i].Split(':');
string proxyServer = proxyAdrs[0];
int proxyPort = Convert.ToInt32(proxyAdrs[1]);
if(proxyAdrs.Length > 3)
{
if(proxyAdrs[2] != null)
item.Username = proxyAdrs[2];
if (proxyAdrs[3] != null)
item.Password = proxyAdrs[3];
}
else
{
if(proxyAdrs[2] != null)
item.Password = proxyAdrs[2];
}
try
{
objCommonDD = new CommonDropDownBLL();
objCommonDDEntity = new CommonDropdownEntity();
//string strState=contextKey.ToString();
string[] contextKeySplit = contextKey.Split('^');
string strState = contextKeySplit[0].ToString();
string strPin = contextKeySplit[1].ToString();
objCommonDDEntity.TableName = "PCOM_PINCODES";
objCommonDDEntity.DeleteField = "";
objCommonDDEntity.TextField = "RTRIM(PIN_CITY_NAME) AS PC_DESC";
objCommonDDEntity.ValueField = "DISTINCT PIN_CITY_CODE AS PC_CODE";
objCommonDDEntity.StrCondition = " AND PIN_COUNTRY_CODE='IND' AND UPPER(PIN_CITY_NAME) LIKE UPPER('" + prefixText + "%') AND PIN_STATE_NAME='" + strState + "' AND PIN_CODE='" + strPin + "' ORDER BY PC_DESC";
DataTable dtCity = new DataTable();
dtCity = objCommonDD.GetData(objCommonDDEntity);
string[] items = new string[dtCity.Rows.Count];
int i = 0;
for (i = 0; i < dtCity.Rows.Count; i++)
{
items.SetValue(dtCity.Rows[i]["PC_DESC"].ToString(), i);
}
return items;
}

Make Code Fast Execute - replace For loops

It takes lot of time to execute these loops due to for loop implementation
How can I replace it to be more fast, the under laying table do not have much records too, plus I have made the primary keys too , but still the for loops are slow
public List<BusinessLayer.Transactions.CDANumberTracking> GetPOUnusedCDANumberTrackingItems(string code)
{
List<BusinessLayer.Transactions.CDANumberTracking> results = new List<BusinessLayer.Transactions.CDANumberTracking>();
List<Entity.Transactions.CDANumberTracking> SoUsedBagList = new List<Entity.Transactions.CDANumberTracking>();
List<Entity.Transactions.POCDANumberTracking> rejects = new List<SalesOrderModule.Entity.Transactions.POCDANumberTracking>();
List<Entity.Transactions.POCDANumberTracking> returns = new List<SalesOrderModule.Entity.Transactions.POCDANumberTracking>();
List<Entity.Transactions.POCDANumberTracking> rejectList = new List<SalesOrderModule.Entity.Transactions.POCDANumberTracking>();
List<Entity.Transactions.POCDANumberTracking> returnRejectList = new List<SalesOrderModule.Entity.Transactions.POCDANumberTracking>();
List<Entity.Transactions.POCDANumberTracking> SearchList = new List<SalesOrderModule.Entity.Transactions.POCDANumberTracking>();
try
{
if (!InOpenLookup)
(Connection as SQL).BeginTransaction();
DataLayer.Tables.PLSPOCDANumberTrackingDNew sampleTable = new SalesOrderModule.DataLayer.Tables.PLSPOCDANumberTrackingDNew(this.Connection);
sampleTable.SearchCriteria[0].Value = code.Trim();
sampleTable.SearchCriteria[1].Value = (int)0;
List<Entity.Transactions.POCDANumberTracking> results1 = sampleTable.Reads(false);
if (results1.Count > 0)
{
rejectList.AddRange(results1);
}
DataLayer.Tables.PLSPOCDANumberTrackingReturnD sampleTable2 = new SalesOrderModule.DataLayer.Tables.PLSPOCDANumberTrackingReturnD(this.Connection);
sampleTable2.SearchCriteria[0].Value = code.Trim();
List<Entity.Transactions.POCDANumberTracking> results2 = sampleTable2.Reads(false);
if (results2.Count > 0)
{
returnRejectList.AddRange(results2);
}
DataLayer.Tables.PLSPOCDANumberTrackingD sampleTable3 = new SalesOrderModule.DataLayer.Tables.PLSPOCDANumberTrackingD(this.Connection);
sampleTable3.SearchCriteria[0].Value = code.Trim();
SearchList = sampleTable3.Reads(false);
DataLayer.Tables.PSOMCDANumberTrackingD sampleTable4 = new SalesOrderModule.DataLayer.Tables.PSOMCDANumberTrackingD(this.Connection, null);
sampleTable4.SearchCriteria[3].Value = code.Trim();
sampleTable4.SearchCriteria[6].Value = false;
SoUsedBagList = sampleTable4.Read(false);
//process data...
Entity.Transactions.POCDANumberTracking temp;
foreach (Entity.Transactions.POCDANumberTracking rejectItem in rejectList)
{
for (int i = rejectItem.From; i <= rejectItem.To; i++)
{
temp = new SalesOrderModule.Entity.Transactions.POCDANumberTracking();
temp.From = i;
temp.To = i;
temp.Code = rejectItem.Code.Trim();
temp.GrnNo = rejectItem.GrnNo.Trim();
temp.WbcNo = rejectItem.WbcNo.Trim();
rejects.Add(temp);
}
}
//returns
foreach (Entity.Transactions.POCDANumberTracking returnItem in returnRejectList)
{
for (int i = returnItem.From; i <= returnItem.To; i++)
{
temp = new SalesOrderModule.Entity.Transactions.POCDANumberTracking();
temp.From = i;
temp.To = i;
temp.Code = returnItem.Code.Trim();
temp.GrnNo = returnItem.GrnNo.Trim();
temp.WbcNo = returnItem.WbcNo.Trim();
returns.Add(temp);
}
}
Entity.Transactions.CDANumberTracking temp2;
Entity.Transactions.CDANumberTracking temp3;
Entity.Transactions.POCDANumberTracking temp4;
foreach (Entity.Transactions.POCDANumberTracking searchItem in SearchList)
{
for (int i = searchItem.From; i <= searchItem.To; i++)
{
temp = null;
temp3 = null;
temp4 = null;
//check if the bag is on reject list
temp = rejects.Find(delegate(Entity.Transactions.POCDANumberTracking tc) { return (tc.From == i && tc.WbcNo.Trim().ToUpper() == searchItem.WbcNo.Trim().ToUpper() && tc.GrnNo.Trim().ToUpper() == searchItem.GrnNo.Trim().ToUpper()); });
if (temp != null)
continue;
//check if the bag is on return list
temp4 = returns.Find(delegate(Entity.Transactions.POCDANumberTracking tcc) { return (tcc.From == i && tcc.GrnNo.Trim().ToUpper() == searchItem.GrnNo.Trim().ToUpper()); });
if (temp4 != null)
continue;
//check if the bag is alredy used in So module...
temp3 = SoUsedBagList.Find(delegate(Entity.Transactions.CDANumberTracking cda) { return (cda.Code.Trim().ToUpper() == searchItem.Code.Trim().ToUpper() && cda.BagNo == searchItem.From); });
if (temp3 != null)
continue;
temp2 = new SalesOrderModule.Entity.Transactions.CDANumberTracking();
temp2.BagNo = i;
temp2.Code = searchItem.Code.Trim();
temp2.LineNo = 0;
temp2.Location = string.Empty;
temp2.WbcNo = string.Empty;
temp2.ID = null;
temp2.IsReturned = false;
temp2.IsSelected = false;
temp2.ItemNo = string.Empty;
temp2.Status = SalesOrderModule.Entity.ModifyStatus.New;
results.Add(BusinessLayer.Transactions.CDANumberTracking.GetCDANumberTracking(this, temp2, null));
}
}
if (!InOpenLookup)
(Connection as SQL).EndTransaction();
}
catch (Exception er)
{
if (!InOpenLookup)
(Connection as SQL).Rollback();
throw er;
}
return results;
}
the for loop under second for each need to placed ... need some help
You should factor out of the inner loop everything you can. As the code stands right now, you are unecessarily repeating the following operations:
returnItem.Code.Trim();
returnItem.GrnNo.Trim();
returnItem.WbcNo.Trim();
I have nowhere near enough information to judge if this will have any performance impact.
Other suspects are new SalesOrderModule.Entity.Transactions.POCDANumberTracking() and returns.Add(temp). If returns is somekind of ordered list, then this could have a considerable performance hit. If its a simple List then it shouldn't and there isn't much you could do to improve it anyways.
Concerning the constructor, only you know how expensive it is but there is not much you can do to avoid it either.
All that said, your code would look something like this:
Entity.Transactions.POCDANumberTracking temp;
foreach (Entity.Transactions.POCDANumberTracking returnItem in returnRejectList)
{
var code = returnItem.Code.Trim();
var grnNo = returnItem.GrnNo.Trim();
var wbcNo = returnItem.WbcNo.Trim();
for (int i = returnItem.From; i <= returnItem.To; i++)
{
temp = new SalesOrderModule.Entity.Transactions.POCDANumberTracking();
temp.From = i;
temp.To = i;
temp.Code = code;
temp.GrnNo = grnNo;
temp.WbcNo = wbcNo;
returns.Add(temp);
}
}
I have to limit the entries coming under the foreach loops, that is best way by debugging the code
so the data layer codes referring in the
sampleTable.Reads(false);
sampleTable2.Reads(false);
sampleTable3.Reads(false);
sampleTable4.Reads(false);
need to modified by including the Item for search (I mean the SQL STATEMENTS)

mailmerge with visto how to get each record of MailMerge.DataSource.DataFields

I' have a Project that needs to do a mailmerge, I'm performing this with VSTO. I need to check if all records on the MailMerge.DataSource.DataFields are ok. i'm doing that with this code.
public void verificarPersonas(Word.Document Doc)
{
ThisAddIn ThisAddIn = Globals.ThisAddIn;
List<Personas> miListaPersonas = new List<Personas>();
decimal nRecords = Doc.MailMerge.DataSource.RecordCount;
if (nRecords == 0)
{
cambiarEstado("Empty db or documento does'n prepared for mail merge", false);
}
else
{
string fieldIdentificacion = persParm("Identificacion");
string fieldNombre = persParm("Nombres");
string fieldApellido = persParm("Apellidos");
string fieldEmail = persParm("Email");
string fieldDireccion = persParm("Direccion");
string fieldTelefono = persParm("Telefono");
if (String.IsNullOrEmpty(fieldIdentificacion) || String.IsNullOrEmpty(fieldNombre))
{
cambiarEstado("", false);
return;
}
else
{
for (int i = 1; i <= nRecords; i++)
{
Doc.MailMerge.DataSource.FirstRecord = i;
Doc.MailMerge.DataSource.LastRecord = i;
// Here Allways get the first record
dynamic fields = Doc.MailMerge.DataSource.DataFields;
// ________________________________
Personas personaActual = new Personas();
personaActual.IdPersona = 0;
try
{
personaActual.Identificacion = fields(fieldIdentificacion).value;
personaActual.Nombres = fields(fieldNombre).value;
personaActual.Apellidos = (String.IsNullOrEmpty(fieldApellido) ? "" : fields(fieldApellido).value);
personaActual.Email = (String.IsNullOrEmpty(fieldEmail) ? "" : fields(fieldEmail).value);
personaActual.Direccion = (String.IsNullOrEmpty(fieldDireccion) ? "" : fields(fieldDireccion).value);
personaActual.Telefono = (String.IsNullOrEmpty(fieldTelefono) ? "" : fields(fieldTelefono).value);
miListaPersonas.Add(personaActual);
}
catch (Exception e)
{
cambiarEstado(""+e.Message, false);
return;
}
}
string listaPersonasJson = JsonConvert.SerializeObject(miListaPersonas);
string respuesta = wt.getWebData("Personas", "verificarPersonasVSTO", new { personas = listaPersonasJson });
}
}
}
My problem is that dynamic fields = Doc.MailMerge.DataSource.DataFields; allways get the first record.
How can I do to get datafields for the active record ?
After some hours of research and some tries. get that the fields collection of datasource dont move the pointer when you set FirstRecord and Lastrecord, it must be moved using activerecords, using WdMailMergeActiveRecord enumeration, sonething like this:
int nRecords = Doc.MailMerge.DataSource.RecordCount;
for (int i = 1; i <= nRecords; i++)
{
Doc.MailMerge.DataSource.FirstRecord = i; //It doesn't work
Doc.MailMerge.DataSource.LastRecord = i; // it doesn't work
Doc.MailMerge.DataSource.ActiveRecord = (i == 1 ?
Word.WdMailMergeActiveRecord.wdFirstDataSourceRecord :Word.WdMailMergeActiveRecord.wdNextDataSourceRecord);
Doc.MailMerge.DataSource.ActiveRecord = (i == nRecords ? Word.WdMailMergeActiveRecord.wdLastDataSourceRecord : Doc.MailMerge.DataSource.ActiveRecord);
dynamic fields = Doc.MailMerge.DataSource.DataFields;
}

More Efficient Way To Split a Balanced String C#

I've done this with balancing Regex's before when I only had one balancing character...but with more balancing characters it gets more complicated and uglier.
For my current purpose, I instead wrote an method to do this by tokenizing the string but it's terribly slow (and terribly inefficient) The most expensive part seems to be the gratuitous Substring usage I'm doing (yeah I know it's bad).
Basically, I want to take the following
hello("(abc d)", efg (hijk)) and,some more<%lmn, "o(\")pq", (xy(z))%>
and end up with
hello("(abc d)", efg (hijk))
[space] (the actual character)
and
,
some more
<%lmn, "o()pq", (xy(z))%>
In other words, I'm splitting on (and I want these included in the array results)
[space]
,
....and I have "balanced grouping strings"
" "
( )
<% %>
...and I have escape characters
\
I'd prefer not to write a whole big parser for this purpose...
Here's the code:
public static IEnumerable<string> SplitNotEnclosed(this string s, IEnumerable<string> separators, Dictionary<string, string> enclosingValues = null, IEnumerable<char> escapeCharacters = null, bool includeSeparators = false, StringComparison comparisonType = StringComparison.Ordinal)
{
var results = new List<string>();
var enclosureStack = new Stack<KeyValuePair<string, string>>();
bool atEscapedCharacter = false;
if (escapeCharacters == null) escapeCharacters = new[] { '\\' };
if (enclosingValues == null) enclosingValues = new[] { "\"" }.ToDictionary(i => i);
var orderedEnclosingValues = enclosingValues.OrderByDescending(i => i.Key.Length).ToArray();
separators = separators.OrderByDescending(v => v.Length).ToArray();
var currentPart = new StringBuilder();
while (s.Length > 0)
{
int addToIndex = 0;
var newEnclosingValue = orderedEnclosingValues.FirstOrDefault(v => s.StartsWith(v.Key, comparisonType));
if (enclosureStack.Count > 0 && !atEscapedCharacter && s.StartsWith(enclosureStack.Peek().Value))
{
addToIndex = enclosureStack.Peek().Value.Length;
enclosureStack.Pop();
}
else if (newEnclosingValue.Key != null && !atEscapedCharacter)
{
enclosureStack.Push(newEnclosingValue);
addToIndex = newEnclosingValue.Key.Length;
}
else if (escapeCharacters.Contains(s[0]) && enclosureStack.Count > 0)
{
atEscapedCharacter = !atEscapedCharacter;
addToIndex = 1;
}
else if (enclosureStack.Count > 0)
{
atEscapedCharacter = false;
addToIndex = 1;
}
if (enclosureStack.Count == 0)
{
string separator = separators.FirstOrDefault(v => s.StartsWith(v, comparisonType));
if (separator != null)
{
if (currentPart.Length > 0) results.Add(currentPart.ToString());
results.Add(separator);
s = s.Substring(separator.Length);
currentPart = new StringBuilder();
addToIndex = 0;
}
else
{
addToIndex = 1;
}
}
currentPart.Append(s.Substring(0, addToIndex));
s = s.Substring(addToIndex);
}
if (currentPart.Length > 0) results.Add(currentPart.ToString());
if (!includeSeparators)
{
results = results.Except(separators).ToList();
}
return results.ToArray();
}

Reading CSV file and storing values into an array

I am trying to read a *.csv-file.
The *.csv-file consist of two columns separated by semicolon (";").
I am able to read the *.csv-file using StreamReader and able to separate each line by using the Split() function. I want to store each column into a separate array and then display it.
Is it possible to do that?
You can do it like this:
using System.IO;
static void Main(string[] args)
{
using(var reader = new StreamReader(#"C:\test.csv"))
{
List<string> listA = new List<string>();
List<string> listB = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(';');
listA.Add(values[0]);
listB.Add(values[1]);
}
}
}
My favourite CSV parser is one built into .NET library. This is a hidden treasure inside Microsoft.VisualBasic namespace.
Below is a sample code:
using Microsoft.VisualBasic.FileIO;
var path = #"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
// Skip the row with the column names
csvParser.ReadLine();
while (!csvParser.EndOfData)
{
// Read current line fields, pointer moves to the next line.
string[] fields = csvParser.ReadFields();
string Name = fields[0];
string Address = fields[1];
}
}
Remember to add reference to Microsoft.VisualBasic
More details about the parser is given here: http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html
LINQ way:
var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
select (from piece in line
select piece);
^^Wrong - Edit by Nick
It appears the original answerer was attempting to populate csv with a 2 dimensional array - an array containing arrays. Each item in the first array contains an array representing that line number with each item in the nested array containing the data for that specific column.
var csv = from line in lines
select (line.Split(',')).ToArray();
Just came across this library: https://github.com/JoshClose/CsvHelper
Very intuitive and easy to use. Has a nuget package too which made is quick to implement: https://www.nuget.org/packages/CsvHelper/27.2.1. Also appears to be actively maintained which I like.
Configuring it to use a semi-colon is easy: https://github.com/JoshClose/CsvHelper/wiki/Custom-Configurations
You can't create an array immediately because you need to know the number of rows from the beginning (and this would require to read the csv file twice)
You can store values in two List<T> and then use them or convert into an array using List<T>.ToArray()
Very simple example:
var column1 = new List<string>();
var column2 = new List<string>();
using (var rd = new StreamReader("filename.csv"))
{
while (!rd.EndOfStream)
{
var splits = rd.ReadLine().Split(';');
column1.Add(splits[0]);
column2.Add(splits[1]);
}
}
// print column1
Console.WriteLine("Column 1:");
foreach (var element in column1)
Console.WriteLine(element);
// print column2
Console.WriteLine("Column 2:");
foreach (var element in column2)
Console.WriteLine(element);
N.B.
Please note that this is just a very simple example. Using string.Split does not account for cases where some records contain the separator ; inside it.
For a safer approach, consider using some csv specific libraries like CsvHelper on nuget.
I usually use this parser from codeproject, since there's a bunch of character escapes and similar that it handles for me.
Here is my variation of the top voted answer:
var contents = File.ReadAllText(filename).Split('\n');
var csv = from line in contents
select line.Split(',').ToArray();
The csv variable can then be used as in the following example:
int headerRows = 5;
foreach (var row in csv.Skip(headerRows)
.TakeWhile(r => r.Length > 1 && r.Last().Trim().Length > 0))
{
String zerothColumnValue = row[0]; // leftmost column
var firstColumnValue = row[1];
}
If you need to skip (head-)lines and/or columns, you can use this to create a 2-dimensional array:
var lines = File.ReadAllLines(path).Select(a => a.Split(';'));
var csv = (from line in lines
select (from col in line
select col).Skip(1).ToArray() // skip the first column
).Skip(2).ToArray(); // skip 2 headlines
This is quite useful if you need to shape the data before you process it further (assuming the first 2 lines consist of the headline, and the first column is a row title - which you don't need to have in the array because you just want to regard the data).
N.B. You can easily get the headlines and the 1st column by using the following code:
var coltitle = (from line in lines
select line.Skip(1).ToArray() // skip 1st column
).Skip(1).Take(1).FirstOrDefault().ToArray(); // take the 2nd row
var rowtitle = (from line in lines select line[0] // take 1st column
).Skip(2).ToArray(); // skip 2 headlines
This code example assumes the following structure of your *.csv file:
Note: If you need to skip empty rows - which can by handy sometimes, you can do so by inserting
where line.Any(a=>!string.IsNullOrWhiteSpace(a))
between the from and the select statement in the LINQ code examples above.
You can use Microsoft.VisualBasic.FileIO.TextFieldParser dll in C# for better performance
get below code example from above article
static void Main()
{
string csv_file_path=#"C:\Users\Administrator\Desktop\test.csv";
DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);
Console.WriteLine("Rows count:" + csvData.Rows.Count);
Console.ReadLine();
}
private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = true;
string[] colFields = csvReader.ReadFields();
foreach (string column in colFields)
{
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
}
return csvData;
}
Hi all, I created a static class for doing this.
+ column check
+ quota sign removal
public static class CSV
{
public static List<string[]> Import(string file, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
{
return ReadCSVFile(file, csvDelimiter, ignoreHeadline, removeQuoteSign);
}
private static List<string[]> ReadCSVFile(string filename, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
{
string[] result = new string[0];
List<string[]> lst = new List<string[]>();
string line;
int currentLineNumner = 0;
int columnCount = 0;
// Read the file and display it line by line.
using (System.IO.StreamReader file = new System.IO.StreamReader(filename))
{
while ((line = file.ReadLine()) != null)
{
currentLineNumner++;
string[] strAr = line.Split(csvDelimiter);
// save column count of dirst line
if (currentLineNumner == 1)
{
columnCount = strAr.Count();
}
else
{
//Check column count of every other lines
if (strAr.Count() != columnCount)
{
throw new Exception(string.Format("CSV Import Exception: Wrong column count in line {0}", currentLineNumner));
}
}
if (removeQuoteSign) strAr = RemoveQouteSign(strAr);
if (ignoreHeadline)
{
if(currentLineNumner !=1) lst.Add(strAr);
}
else
{
lst.Add(strAr);
}
}
}
return lst;
}
private static string[] RemoveQouteSign(string[] ar)
{
for (int i = 0;i< ar.Count() ; i++)
{
if (ar[i].StartsWith("\"") || ar[i].StartsWith("'")) ar[i] = ar[i].Substring(1);
if (ar[i].EndsWith("\"") || ar[i].EndsWith("'")) ar[i] = ar[i].Substring(0,ar[i].Length-1);
}
return ar;
}
}
I have spend few hours searching for a right library, but finally I wrote my own code :)
You can read file (or database) with whatever tools you want and then apply the following routine to each line:
private static string[] SmartSplit(string line, char separator = ',')
{
var inQuotes = false;
var token = "";
var lines = new List<string>();
for (var i = 0; i < line.Length; i++) {
var ch = line[i];
if (inQuotes) // process string in quotes,
{
if (ch == '"') {
if (i<line.Length-1 && line[i + 1] == '"') {
i++;
token += '"';
}
else inQuotes = false;
} else token += ch;
} else {
if (ch == '"') inQuotes = true;
else if (ch == separator) {
lines.Add(token);
token = "";
} else token += ch;
}
}
lines.Add(token);
return lines.ToArray();
}
var firstColumn = new List<string>();
var lastColumn = new List<string>();
// your code for reading CSV file
foreach(var line in file)
{
var array = line.Split(';');
firstColumn.Add(array[0]);
lastColumn.Add(array[1]);
}
var firstArray = firstColumn.ToArray();
var lastArray = lastColumn.ToArray();
Here's a special case where one of data field has semicolon (";") as part of it's data in that case most of answers above will fail.
Solution in that case will be
string[] csvRows = System.IO.File.ReadAllLines(FullyQaulifiedFileName);
string[] fields = null;
List<string> lstFields;
string field;
bool quoteStarted = false;
foreach (string csvRow in csvRows)
{
lstFields = new List<string>();
field = "";
for (int i = 0; i < csvRow.Length; i++)
{
string tmp = csvRow.ElementAt(i).ToString();
if(String.Compare(tmp,"\"")==0)
{
quoteStarted = !quoteStarted;
}
if (String.Compare(tmp, ";") == 0 && !quoteStarted)
{
lstFields.Add(field);
field = "";
}
else if (String.Compare(tmp, "\"") != 0)
{
field += tmp;
}
}
if(!string.IsNullOrEmpty(field))
{
lstFields.Add(field);
field = "";
}
// This will hold values for each column for current row under processing
fields = lstFields.ToArray();
}
The open-source Angara.Table library allows to load CSV into typed columns, so you can get the arrays from the columns. Each column can be indexed both by name or index. See http://predictionmachines.github.io/Angara.Table/saveload.html.
The library follows RFC4180 for CSV; it enables type inference and multiline strings.
Example:
using System.Collections.Immutable;
using Angara.Data;
using Angara.Data.DelimitedFile;
...
ReadSettings settings = new ReadSettings(Delimiter.Semicolon, false, true, null, null);
Table table = Table.Load("data.csv", settings);
ImmutableArray<double> a = table["double-column-name"].Rows.AsReal;
for(int i = 0; i < a.Length; i++)
{
Console.WriteLine("{0}: {1}", i, a[i]);
}
You can see a column type using the type Column, e.g.
Column c = table["double-column-name"];
Console.WriteLine("Column {0} is double: {1}", c.Name, c.Rows.IsRealColumn);
Since the library is focused on F#, you might need to add a reference to the FSharp.Core 4.4 assembly; click 'Add Reference' on the project and choose FSharp.Core 4.4 under "Assemblies" -> "Extensions".
I have been using csvreader.com(paid component) for years, and I have never had a problem. It is solid, small and fast, but you do have to pay for it. You can set the delimiter to whatever you like.
using (CsvReader reader = new CsvReader(s) {
reader.Settings.Delimiter = ';';
reader.ReadHeaders(); // if headers on a line by themselves. Makes reader.Headers[] available
while (reader.ReadRecord())
... use reader.Values[col_i] ...
}
I am just student working on my master's thesis, but this is the way I solved it and it worked well for me. First you select your file from directory (only in csv format) and then you put the data into the lists.
List<float> t = new List<float>();
List<float> SensorI = new List<float>();
List<float> SensorII = new List<float>();
List<float> SensorIII = new List<float>();
using (OpenFileDialog dialog = new OpenFileDialog())
{
try
{
dialog.Filter = "csv files (*.csv)|*.csv";
dialog.Multiselect = false;
dialog.InitialDirectory = ".";
dialog.Title = "Select file (only in csv format)";
if (dialog.ShowDialog() == DialogResult.OK)
{
var fs = File.ReadAllLines(dialog.FileName).Select(a => a.Split(';'));
int counter = 0;
foreach (var line in fs)
{
counter++;
if (counter > 2) // Skip first two headder lines
{
this.t.Add(float.Parse(line[0]));
this.SensorI.Add(float.Parse(line[1]));
this.SensorII.Add(float.Parse(line[2]));
this.SensorIII.Add(float.Parse(line[3]));
}
}
}
}
catch (Exception exc)
{
MessageBox.Show(
"Error while opening the file.\n" + exc.Message,
this.Text,
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
}
This is my 2 simple static methods to convert text from csv file to List<List<string>> and vice versa. Each method use row convertor.
This code should take into account all the possibilities of the csv file. You can define own csv separator and this methods try to correct escape double 'quote' char, and deals with the situation when all text in quotes are one cell and csv separator is inside quoted string including multiple lines in one cell and can ignore empty rows.
Last method is only for testing. So you can ignore it, or test your own, or others solution with this test method :). For testing I used this hard csv with 2 rows on 4 lines:
0,a,""bc,d
"e, f",g,"this,is, o
ne ""lo
ng, cell""",h
This is final code. For simplicity, I removed all try catch blocks.
using System;
using System.Collections.Generic;
using System.Linq;
public static class Csv {
public static string FromListToString(List<List<string>> csv, string separator = ",", char quotation = '"', bool returnFirstRow = true)
{
string content = "";
for (int row = 0; row < csv.Count; row++) {
content += (row > 0 ? Environment.NewLine : "") + RowFromListToString(csv[row], separator, quotation);
}
return content;
}
public static List<List<string>> FromStringToList(string content, string separator = ",", char quotation = '"', bool returnFirstRow = true, bool ignoreEmptyRows = true)
{
List<List<string>> csv = new List<List<string>>();
string[] rows = content.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
if (rows.Length <= (returnFirstRow ? 0 : 1)) { return csv; }
List<string> csvRow = null;
for (int rowIndex = 0; rowIndex < rows.Length; rowIndex++) {
(List<string> row, bool rowClosed) = RowFromStringToList(rows[rowIndex], csvRow, separator, quotation);
if (rowClosed) { if (!ignoreEmptyRows || row.Any(rowItem => rowItem.Length > 0)) { csv.Add(row); csvRow = null; } } // row ok, add to list
else { csvRow = row; } // not fully created, continue
}
if (!returnFirstRow) { csv.RemoveAt(0); } // remove header
return csv;
}
public static string RowFromListToString(List<string> csvData, string separator = ",", char quotation = '"')
{
csvData = csvData.Select(element =>
{
if (element.Contains(quotation)) {
element = element.Replace(quotation.ToString(), quotation.ToString() + quotation.ToString());
}
if (element.Contains(separator) || element.Contains(Environment.NewLine)) {
element = "\"" + element + "\"";
}
return element;
}).ToList();
return string.Join(separator, csvData);
}
public static (List<string>, bool) RowFromStringToList(string csvRow, List<string> continueWithRow = null, string separator = ",", char quotation = '"')
{
bool rowClosed = true;
if (continueWithRow != null && continueWithRow.Count > 0) {
// in previous result quotation are fixed so i need convert back to double quotation
string previousCell = quotation.ToString() + continueWithRow.Last().Replace(quotation.ToString(), quotation.ToString() + quotation.ToString()) + Environment.NewLine;
continueWithRow.RemoveAt(continueWithRow.Count - 1);
csvRow = previousCell + csvRow;
}
char tempQuote = (char)162;
while (csvRow.Contains(tempQuote)) { tempQuote = (char)(tempQuote + 1); }
char tempSeparator = (char)(tempQuote + 1);
while (csvRow.Contains(tempSeparator)) { tempSeparator = (char)(tempSeparator + 1); }
csvRow = csvRow.Replace(quotation.ToString() + quotation.ToString(), tempQuote.ToString());
if(csvRow.Split(new char[] { quotation }, StringSplitOptions.None).Length % 2 == 0) { rowClosed = !rowClosed; }
string[] csvSplit = csvRow.Split(new string[] { separator }, StringSplitOptions.None);
List<string> csvList = csvSplit
.ToList()
.Aggregate("",
(string row, string item) => {
if (row.Count((ch) => ch == quotation) % 2 == 0) { return row + (row.Length > 0 ? tempSeparator.ToString() : "") + item; }
else { return row + separator + item; }
},
(string row) => row.Split(tempSeparator).Select((string item) => item.Trim(quotation).Replace(tempQuote, quotation))
).ToList();
if (continueWithRow != null && continueWithRow.Count > 0) {
return (continueWithRow.Concat(csvList).ToList(), rowClosed);
}
return (csvList, rowClosed);
}
public static bool Test()
{
string csvText = "0,a,\"\"bc,d" + Environment.NewLine + "\"e, f\",g,\"this,is, o" + Environment.NewLine + "ne \"\"lo" + Environment.NewLine + "ng, cell\"\"\",h";
List<List<string>> csvList = new List<List<string>>() { new List<string>() { "0", "a", "\"bc", "d" }, new List<string>() { "e, f", "g", "this,is, o" + Environment.NewLine + "ne \"lo" + Environment.NewLine + "ng, cell\"", "h" } };
List<List<string>> csvTextAsList = Csv.FromStringToList(csvText);
bool ok = Enumerable.SequenceEqual(csvList[0], csvTextAsList[0]) && Enumerable.SequenceEqual(csvList[1], csvTextAsList[1]);
string csvListAsText = Csv.FromListToString(csvList);
return ok && csvListAsText == csvText;
}
}
Usage examples:
// get List<List<string>> representation of csv
var csvFromText = Csv.FromStringToList(csvAsText);
// read csv file with custom separator and quote
// return no header and ignore empty rows
var csvFile = File.ReadAllText(csvFileFullPath);
var csvFromFile = Csv.FromStringToList(csvFile, ";", '"', false, false);
// get text representation of csvData from List<List<string>>
var csvAsText = Csv.FromListToString(csvData);
Notes:
This: char tempQuote = (char)162; is first rare character from ASCI table. The script searches for this, or the first next few ascii character that is NOT in the text and uses it as a temporary escape and quote characters.
Still wrong. You need to compensate for "" in quotes.
Here is my solution Microsoft style csv.
/// <summary>
/// Microsoft style csv file. " is the quote character, "" is an escaped quote.
/// </summary>
/// <param name="fileName"></param>
/// <param name="sepChar"></param>
/// <param name="quoteChar"></param>
/// <param name="escChar"></param>
/// <returns></returns>
public static List<string[]> ReadCSVFileMSStyle(string fileName, char sepChar = ',', char quoteChar = '"')
{
List<string[]> ret = new List<string[]>();
string[] csvRows = System.IO.File.ReadAllLines(fileName);
foreach (string csvRow in csvRows)
{
bool inQuotes = false;
List<string> fields = new List<string>();
string field = "";
for (int i = 0; i < csvRow.Length; i++)
{
if (inQuotes)
{
// Is it a "" inside quoted area? (escaped litteral quote)
if(i < csvRow.Length - 1 && csvRow[i] == quoteChar && csvRow[i+1] == quoteChar)
{
i++;
field += quoteChar;
}
else if(csvRow[i] == quoteChar)
{
inQuotes = false;
}
else
{
field += csvRow[i];
}
}
else // Not in quoted region
{
if (csvRow[i] == quoteChar)
{
inQuotes = true;
}
if (csvRow[i] == sepChar)
{
fields.Add(field);
field = "";
}
else
{
field += csvRow[i];
}
}
}
if (!string.IsNullOrEmpty(field))
{
fields.Add(field);
field = "";
}
ret.Add(fields.ToArray());
}
return ret;
}
}
I have a library that is doing exactly you need.
Some time ago I had wrote simple and fast enough library for work with CSV files. You can find it by the following link: https://github.com/ukushu/DataExporter/blob/master/Csv.cs
It works with CSV like with 2 dimensions array. Exactly like you need.
As example, in case of you need all of values of 3rd row only you need is to write:
Csv csv = new Csv();
csv.FileOpen("c:\\file1.csv");
var allValuesOf3rdRow = csv.Rows[2];
or to read 2nd cell of 3rd row:
var value = csv.Rows[2][1];
Headers are required in csv for json conversion in the below code
You can use below code as is without making any changes.
This code will work with two row headers or with one row header.
Below code reads the uploaded IForm File and converts to memory stream.
If you want to use file path instead of uploaded file you can replace
new StreamReader(ms, System.Text.Encoding.UTF8, true)) with new StreamReader("../../examplefilepath");
using (var ms = new MemoryStream())
{
administrativesViewModel.csvFile.CopyTo(ms);
ms.Position = 0;
using (StreamReader csvReader = new StreamReader(ms, System.Text.Encoding.UTF8, true))
{
List<string> lines = new List<string>();
while (!csvReader.EndOfStream)
{
var line = csvReader.ReadLine();
var values = line.Split(';');
if (values[0] != "" && values[0] != null)
{
lines.Add(values[0]);
}
}
var csv = new List<string[]>();
foreach (string item in lines)
{
csv.Add(item.Split(','));
}
var properties = lines[0].Split(',');
int csvI = 1;
var listObjResult = new List<Dictionary<string, string>>();
if (lines.Count() > 1)
{
var ln = lines[0].Substring(0, lines[0].Count() - 1);
var ln1 = lines[1].Substring(0, lines[1].Count() - 1);
var lnSplit = ln.Split(',');
var ln1Split = ln1.Split(',');
if (lnSplit.Count() != ln1Split.Count())
{
properties = lines[1].Split(',');
csvI = 2;
}
}
for (int i = csvI; i < csv.Count(); i++)
{
var objResult = new Dictionary<string, string>();
if (csvI > 0)
{
var splitProp = lines[0].Split(":");
if (splitProp.Count() > 1)
{
if (splitProp[0] != "" && splitProp[0] != null && splitProp[1] != "" && splitProp[1] != null)
{
objResult.Add(splitProp[0], splitProp[1]);
}
}
}
for (int j = 0; j < properties.Length; j++)
if (!properties[j].Contains(":"))
{
objResult.Add(properties[j], csv[i][j]);
}
listObjResult.Add(objResult);
}
var result = JsonConvert.SerializeObject(listObjResult);
var result2 = JArray.Parse(result);
Console.WriteLine(result2);
}
}
look at this
using CsvFramework;
using System.Collections.Generic;
namespace CvsParser
{
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public int Quantity { get; set; }
public int Amount { get; set; }
public List<OrderItem> OrderItems { get; set; }
}
public class Address
{
public int Id { get; set; }
public int CustomerId { get; set; }
public string Name { get; set; }
}
public class OrderItem
{
public int Id { get; set; }
public int OrderId { get; set; }
public string ProductName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var customerLines = System.IO.File.ReadAllLines(#"Customers.csv");
var orderLines = System.IO.File.ReadAllLines(#"Orders.csv");
var orderItemLines = System.IO.File.ReadAllLines(#"OrderItemLines.csv");
CsvFactory.Register<Customer>(builder =>
{
builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
builder.Add(a => a.Name).Type(typeof(string)).Index(1);
builder.AddNavigation(n => n.Orders).RelationKey<Order, int>(k => k.CustomerId);
}, false, ',', customerLines);
CsvFactory.Register<Order>(builder =>
{
builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
builder.Add(a => a.CustomerId).Type(typeof(int)).Index(1);
builder.Add(a => a.Quantity).Type(typeof(int)).Index(2);
builder.Add(a => a.Amount).Type(typeof(int)).Index(3);
builder.AddNavigation(n => n.OrderItems).RelationKey<OrderItem, int>(k => k.OrderId);
}, true, ',', orderLines);
CsvFactory.Register<OrderItem>(builder =>
{
builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
builder.Add(a => a.OrderId).Type(typeof(int)).Index(1);
builder.Add(a => a.ProductName).Type(typeof(string)).Index(2);
}, false, ',', orderItemLines);
var customers = CsvFactory.Parse<Customer>();
}
}
}

Categories

Resources