I have a problem.
I have an Excel File where sometimes the same customer is in 2 rows.
But not always.
Its like:
Click
Now, i want to create a DataGrid in C# which can list this in one row like:
Click
I know it would be easier to change the Excel file, but assume it wouldnt work that way(we get the file like this and we cant change it)
I know i could too just make another Excel File and make it with Excel(already did it this way, but we would need it more as C#)
Now i am at this point:
private void button2_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog() { Filter = "Excel Arbeitsmappe |*.xlsx", ValidateNames = true };
if (ofd.ShowDialog() == DialogResult.OK)
textBox1.Text = ofd.SafeFileName;
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = false;
string filename = ofd.FileName;
Excel.Workbook workbook = excelApp.Workbooks.Open(filename);
Excel.Worksheet worksheet = workbook.Worksheets[1];
dataGridView1.ColumnCount = 2;
dataGridView1.Columns[0].Name = "Number";
dataGridView1.Columns[1].Name = "Street";
int rows = worksheet.UsedRange.Rows.Count;
for (int i = 2; i <= rows; i++)
{
string combinehr = worksheet.Cells[i, 150].Text + worksheet.Cells[i, 151].Text;
dataGridView1.Rows.Add(worksheet.Cells[i,29].Text, combinehr);
}
}
How do i expand it that it works like i want?
I would be so grateful
(sorry for the english)
With a reference to ExcelDataReader, ExcelDataReader.DataSet and DataSetExtensions (.Net) you can read the Excel file pretty easy into a DataSet, then you just have to work with the logic:
Input file:
using System;
using System.Data;
using System.IO;
using System.Linq;
using ExcelDataReader;
public DataTable GetTableFromExcel(string filePath)
{
DataSet ds = new DataSet();
using (var stream = System.IO.File.Open(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
ds = reader.AsDataSet();
}
}
DataTable table = new DataTable();
table.Columns.Add(new DataColumn("CustomerNr"));
table.Columns.Add(new DataColumn("Address"));
// Set column names
for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
{
// DataColumn.ColumnName can't be empty when DataColumn is part
// of a DataTable (throws ArgumentException)
string columnName = ds.Tables[0].Rows[0][i].ToString();
if (string.IsNullOrWhiteSpace(columnName))
{
columnName = $"Column{i}";
}
ds.Tables[0].Columns[i].ColumnName = columnName;
}
// Remove the first row containing the headers
ds.Tables[0].Rows.Remove(ds.Tables[0].Rows[0]);
// I don't have the benchmarks with me right now, but I've tested
// DataTable.Select vs DataTable.AsEnumerable.Select many times
// and the AsEnumerable method its faster, that's why you need the
// reference to System.Data.DataSetExtensions
var enumerableTable = ds.Tables[0].AsEnumerable();
// list of unique products
var products = enumerableTable.Select(row => row.Field<string>("Product")).Distinct();
// Add a column for each product
foreach (string product in products)
{
table.Columns.Add(new DataColumn(product));
}
// list of unique customers
var customerNumbers = enumerableTable.Select(row => row.Field<double>("CustomerNr")).Distinct();
foreach (var customerNumber in customerNumbers)
{
DataRow record = table.NewRow();
record["CustomerNr"] = customerNumber;
record["Address"] = enumerableTable.First(row => row.Field<double>("CustomerNr").Equals(customerNumber))[1];
for (int i = 2; i < table.Columns.Count; i++)
{
DataRow product = enumerableTable.FirstOrDefault(row => row.Field<double>("CustomerNr").Equals(customerNumber)
&& row.Field<string>("Product").Equals(table.Columns[i].ColumnName));
// Quantity = 0 if product is null
record[i] = product?["Quantity"] ?? 0;
}
table.Rows.Add(record);
}
return table;
}
Result DataTable:
The same result as #IvanGarcíaTopete via Microsoft.Office.Interop.Excel.
Class ExcelModel for Excel data:
public class ExcelModel
{
public string CustomerNr { get; set; }
public string Address { get; set; }
public string Product { get; set; }
public string Quantity { get; set; }
}
Read Excel and fill out model:
private void OpenReadExcel()
{
var dlg = new OpenFileDialog();
if (dlg.ShowDialog() != DialogResult.OK) return;
var exApp = new Microsoft.Office.Interop.Excel.Application();
Workbook exWbk = exApp.Workbooks.Open(dlg.FileName);
Worksheet wSh = exWbk.Sheets[1];
int k = 2;
Customers.Clear();
while (wSh.Cells[k, 1].Text != "" && wSh.Cells[k, 1].Value != null)
{
var rowExcelModel = new ExcelModel()
{
CustomerNr = wSh.Cells[k, 1].Text,
Address = wSh.Cells[k, 2].Text,
Product = wSh.Cells[k, 3].Text,
Quantity = wSh.Cells[k, 4].Text
};
Customers.Add(rowExcelModel);
k++;
}
exApp.Quit();
}
Generate Data table:
private void GenerateDataTable()
{
// unique products and customers
var products = Customers.Select(x => x.Product).Distinct().ToList();
var customers = Customers.Select(x => x.CustomerNr).Distinct().ToList();
// columns CustomerNr and Address
var dataTable = new System.Data.DataTable();
dataTable.Columns.Add(new DataColumn("CustomerNr"));
dataTable.Columns.Add(new DataColumn("Address"));
// columns for each product
foreach (var product in products)
{
dataTable.Columns.Add(new DataColumn(product));
}
//fill rows for each customers
foreach (var customer in customers)
{
var row = dataTable.NewRow();
row["CustomerNr"] = customer;
row["Address"] = Customers.Where(x => x.CustomerNr == customer).Select(x => x.Address).FirstOrDefault();
foreach (var product in products)
{
var quantity = Customers.Where(x => x.CustomerNr == customer && x.Product == product)
.Select(x => x.Quantity).FirstOrDefault();
row[product] = quantity ?? "0";
}
dataTable.Rows.Add(row);
}
dataGridView1.DataSource = dataTable;
}
Related
I am taking an excel file to read the fields and pass it to a class, to be able to enter the DB, when I pass dt.AsEnumerable, it is giving me an error in the "Linea" field. This cell sometimes comes with the $ sign. I think that is what is generating the error, so i am trying to replace the character and then convert it to int, since it is an amount field.
using (var streamExcel = System.IO.File.Create(combineFilePath))
{
await file.CopyToAsync(streamExcel);
}
using (var excelWorkbook = new XLWorkbook(combineFilePath))
{
IXLWorksheet workSheet = excelWorkbook.Worksheet(2);
workSheet.Clear(XLClearOptions.AllFormats);
DataTable dt = new DataTable();
bool firstRow = true;
foreach (IXLRow row in workSheet.Rows())
{
//for row number check
if (firstRow)
{
foreach (IXLCell cell in row.Cells())
{
dt.Columns.Add(cell.Value.ToString());
}
firstRow = false;
}
else
{
//Add rows to DataTable.
dt.Rows.Add();
int i = 0;
foreach (IXLCell cell in row.Cells(1, 50))
{
if (cell.Address.ColumnNumber == 11)
{
workSheet.Cell(11, 11).Style.NumberFormat.Format = "#,##0";
cell.SetDataType(XLDataType.Number);
}
dt.Rows[dt.Rows.Count - 1][i] = cell.CachedValue.ToString();
i++;
}
}
}
try
{
var companys = dt.AsEnumerable().Select(row => new Company
{
Name = row.Field<string>("Nombre"),
Rut = row.Field<string>("Rut"),
Address = row.Field<string>("Dirección"),
AddressNumber = row.Field<string>(#"Nº"),
Location = row.Field<string>("Comuna"),
Region = row.Field<string>("Región"),
Giro = row.Field<string>("Giro Cliente"),
Linea = Convert.ToInt32(row.Field<string>("Monto línea Aprobada").Trim().TrimEnd().Replace(#"$", "")),
Observations = row.Field<string>("Observaciones Comité"),
}).ToList();
UserId = _companyService.AddList(companys);
}
catch (Exception e)
{
}
To visualize where it's failing, you could do something like this:
try{
var companysB = dt.AsEnumerable().Select(row => new
{
Name = row.Field<string>("Nombre"),
LineaRaw = row.Field<string>("Monto línea Aprobada"),
LineaProcessed = row.Field<string>("Monto línea Aprobada").Trim().TrimEnd().Replace(#"$", ""),
})
.ToList();
}
Put a breakpoint on 'companysB' and inspect after it's filled. One or more of the LineaRaw / LineaProcessed will not be a number.
The error was when the "Monto línea Aprobada" cell had a blank value, I did this:
var n = 0;
string cellEmty = "";
foreach (DataRow rowEmpty in dt.Rows)
{
cellEmty = rowEmpty["Monto línea Aprobada"].ToString();
if (string.IsNullOrEmpty(cellEmty))
{
cellEmty = "0";
dt.Rows[n].SetField("Monto línea Aprobada", cellEmty);
}
n++;
}
I'm trying to write a parameterized NUnit test that executes twice. Each time it runs, it references a different row in a spreadsheet and gets the username and password based on int rowNum.
class Test
{
//Run the test twice
[Test,TestCase(1),TestCase(2)]
public void T101_LoginTestSuite_Valid(int rowNum)
{
Console.WriteLine(TestContext.CurrentContext.Test.MethodName); //Test Name
Console.WriteLine("Row number "+rowNum);// Value of rowNum
ExcelDataFactory.GetTestDataSet(TestContext.CurrentContext.Test.MethodName);
//Print out the credentials
Console.WriteLine(ExcelDataFactory.ReadData(rowNum,"username"));
Console.WriteLine(ExcelDataFactory.ReadData(rowNum, "password"));
}
}
Here is the excel
The first test case gets username and password correctly.
However the second test case returns blank (If I run this individually it will work!)
Below is the ExcelDataFactory code:
class ExcelDataFactory
{
//Get data from excel
private static DataTable ExcelToDataTable(String filename, String sheetName)
{
//Open file and returns as Stream
FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read);
//CreateOpenXmlReader via ExcelReaderFactory
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream); //.xlsx
//Return as DataSet and set the frist row as column name
DataSet result = excelReader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (_) => new ExcelDataTableConfiguration()
{
UseHeaderRow = true
}
});
DataTableCollection table = result.Tables;
DataTable resultTable = table[sheetName];
//Close FileStream
stream.Close();
//Return
return resultTable;
}
//Put data into a collection
static List<DataCollection> dataCollection = new List<DataCollection>();
public static void PopulateInCollection(string fileName, String sheetName)
{
DataTable table = ExcelToDataTable(fileName,sheetName);
//Iterate through the rows and columns of the Table
for(int row = 1; row <= table.Rows.Count; row++)
{
for (int column = 0; column < table.Columns.Count; column++)
{
DataCollection dataTable = new DataCollection()
{
rowNumber = row,
columnName = table.Columns[column].ColumnName,
columnValue = table.Rows[row - 1][column].ToString()
};
//Add all the details for each row
dataCollection.Add(dataTable);
}
}
}
//Find the correct excel file and sheet
public static void GetTestDataSet(String testName)
{
String[] testNameSplit = testName.Split('_');
String filePath = MyProps.Default.TestData //Add path
+ testNameSplit[1]
+ "."
+ "xlsx";
PopulateInCollection(filePath, testNameSplit[0]);
}
public static string ReadData(int rowNumber, string columnName)
{
try
{
//Retriving Data using LINQ to reduce amount of iterations
string data = (from collectionData in dataCollection
where collectionData.columnName == columnName && collectionData.rowNumber == rowNumber
select collectionData.columnValue).SingleOrDefault();
//var data = dataCollection.Where(collectionData => collectionData.columnName == columnName && collectionData.rowNumber == rowNumber).SingleOrDefault().columnValue;
return data.ToString();
}
catch (Exception e)
{
e.StackTrace.ToString();
return null;
}
}
}
class DataCollection
{
public int rowNumber { get; set; }
public string columnName { get; set; }
public string columnValue { get; set; }
}
I suspect that the ExcelDataFactory.GetTestDataSet method is called in the wrong place, but I really am stumped as to why this is happening. Any ideas would be greatly appreciated.
I did some quick changes to ExcelDataFactory class, I removed the static references and now PopulateInCollection method returns a List that is declared and initialized at the start of the class.
using ExcelDataReader;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Wizuda_Selenium_Test_Automation
{
class ExcelDataFactory
{
List<DataCollection> dataCollection = new List<DataCollection>();
private static DataTable ExcelToDataTable(String filename, String sheetName)
{
//Open file and returns as Stream
FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read);
//CreateOpenXmlReader via ExcelReaderFactory
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream); //.xlsx
//Return as DataSet and set the frist row as column name
DataSet result = excelReader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (_) => new ExcelDataTableConfiguration()
{
UseHeaderRow = true
}
});
DataTableCollection table = result.Tables;
DataTable resultTable = table[sheetName];
//Close FileStream
stream.Close();
//Return
return resultTable;
}
//static List<DataCollection> dataCollection = new List<DataCollection>();
public List<DataCollection> PopulateInCollection(string fileName, String sheetName)
{
dataCollection = new List<DataCollection>();
DataTable table = ExcelToDataTable(fileName,sheetName);
//Iterate through the rows and columns of the Table
for(int row = 1; row <= table.Rows.Count; row++)
{
for (int column = 0; column < table.Columns.Count; column++)
{
DataCollection dataTable = new DataCollection()
{
rowNumber = row,
columnName = table.Columns[column].ColumnName,
columnValue = table.Rows[row - 1][column].ToString()
};
//Add all the details for each row
dataCollection.Add(dataTable);
}
}
return dataCollection;
}
public string ReadData(int rowNumber, string columnName)
{
try
{
//Retriving Data using LINQ to reduce amount of iterations
string data = (from collectionData in dataCollection
where collectionData.columnName == columnName && collectionData.rowNumber == rowNumber
select collectionData.columnValue).SingleOrDefault();
//var data = dataCollection.Where(collectionData => collectionData.columnName == columnName && collectionData.rowNumber == rowNumber).SingleOrDefault().columnValue;
return data.ToString();
}
catch (Exception e)
{
e.StackTrace.ToString();
return null;
}
}
public void GetTestDataSet(String testName)
{
String[] testNameSplit = testName.Split('_');
String filePath = MyProps.Default.TestData //Add path
+ testNameSplit[1] //LoginTestSuite
+ "."
+ "xlsx"; //T101
PopulateInCollection(filePath, testNameSplit[0]);
}
}
class DataCollection
{
public int rowNumber { get; set; }
public string columnName { get; set; }
public string columnValue { get; set; }
}
}
I updated the test to create new instance of ExcelDataFactory
[Test,TestCase(1),TestCase(2)]
public void T101_LoginTestSuite_Valid(int rowNum)
{
ExcelDataFactory excelDataFactory = new ExcelDataFactory();
Console.WriteLine(TestContext.CurrentContext.Test.MethodName);
Console.WriteLine("Row number "+rowNum);
excelDataFactory.GetTestDataSet(TestContext.CurrentContext.Test.MethodName);
Console.WriteLine("username= "+ excelDataFactory.ReadData(rowNum,"username"));
Console.WriteLine("password= "+ excelDataFactory.ReadData(rowNum, "password"));
}
And now the test passes
I guess I need to go back and re-learn about the use static methods, thanks Kritner
how do i compare data in two excel sheet in the same excel worksheet, and display the difference in a new excel sheet using C#, i tried this:
using System.Text;
using System.Data;
using System.Data.OleDb;
using System.IO;
public class ExcelHandler
{
#region Properties
public string Directory { get; set; }
public string FirstFile { get; set; }
public string FirstFileSheetName { get; set; }
public string SecondFile { get; set; }
public string SecondFileSheetName { get; set; }
public DataTable ReturnDataSet { get; set; }
public bool Excel2007 { get; set; }
public bool UseHeader { get; set; }
#endregion
#region Constructor
public ExcelHandler() { }
public ExcelHandler(string Dir, string File1, string File1SheetName, string File2, string File2SheetName)
{
this.Directory = Dir;
this.FirstFile = File1;
this.SecondFile = File2;
this.FirstFileSheetName = File1SheetName;
this.SecondFileSheetName = File2SheetName;
}
#endregion
#region Match Files
public DataTable CheckExcelFiles()
{
DataTable dtRet = new DataTable();
//Read the first excel
try
{
//Read the excel
DataTable dt1 = GetDataTableFromExcel(this.Directory, this.FirstFile, this.FirstFileSheetName);
DataTable dt2 = GetDataTableFromExcel(this.Directory, this.SecondFile, this.SecondFileSheetName);
//Compare two
dtRet = getDifferentRecords(dt1, dt2);
}
catch (Exception ex) { }
return dtRet;
}
//Overload method to write to csv
public void CheckExcelFiles(string strFilePath)
{
DataTable dtRet = new DataTable();
//Read the first excel
try
{
//Read the excel
DataTable dt1 = GetDataTableFromExcel(this.Directory, this.FirstFile, this.FirstFileSheetName);
DataTable dt2 = GetDataTableFromExcel(this.Directory, this.SecondFile, this.SecondFileSheetName);
//Compare two
dtRet = getDifferentRecords(dt1, dt2);
ExportDataTableToExcel(dtRet, strFilePath);
}
catch (Exception ex) { }
}
//Get Datatable reading Excel
private DataTable GetDataTableFromExcel(string strDir, string strFileName, string strSheetName)
{
var fileName = string.Format("{0}\\" + strFileName, strDir);
string connectionString;
//if (Excel2007)
//read a 2007 file
connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=" + (UseHeader == true ? "YES" : "NO") + ";\"", fileName);
//else
//read a 97-2003 file
//connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=" + (UseHeader == true ? "YES" : "NO") + ";\"", fileName);
//var connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0; data source={0}; Extended Properties=Excel 8.0;", fileName);
var adapter = new OleDbDataAdapter("SELECT * FROM [" + strSheetName + "$]", connectionString);
var ds = new DataSet();
adapter.Fill(ds, fileName + strSheetName);
return ds.Tables[fileName + strSheetName];
}
//Compare datatables
private DataTable CompareDataTable(DataTable A, DataTable B)
{
A.PrimaryKey = new DataColumn[] { A.Columns["PK"] };
B.PrimaryKey = new DataColumn[] { B.Columns["PK"] };
A.Merge(B, true); // this will add to A any records that are in B but not A
A.AcceptChanges();
return A.GetChanges(DataRowState.Added); // returns records originally only in B
}
//Provided here http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/23703a85-20c7-4759-806a-fabf4e9f5be6/
//Provided by Guo Surfer
#region Compare two DataTables and return a DataTable with DifferentRecords
/// <summary>
/// Compare two DataTables and return a DataTable with DifferentRecords
/// </summary>
/// <param name="FirstDataTable">FirstDataTable</param>
/// <param name="SecondDataTable">SecondDataTable</param>
/// <returns>DifferentRecords</returns>
public DataTable getDifferentRecords(DataTable FirstDataTable, DataTable SecondDataTable)
{
//Create Empty Table
DataTable ResultDataTable = new DataTable("ResultDataTable");
//use a Dataset to make use of a DataRelation object
using (DataSet ds = new DataSet())
{
//Add tables
ds.Tables.AddRange(new DataTable[] { FirstDataTable.Copy(), SecondDataTable.Copy() });
//Get Columns for DataRelation
DataColumn[] firstColumns = new DataColumn[ds.Tables[0].Columns.Count];
for (int i = 0; i < firstColumns.Length; i++)
{
firstColumns[i] = ds.Tables[0].Columns[i];
}
DataColumn[] secondColumns = new DataColumn[ds.Tables[1].Columns.Count];
for (int i = 0; i < secondColumns.Length; i++)
{
secondColumns[i] = ds.Tables[1].Columns[i];
}
//Create DataRelation
DataRelation r1 = new DataRelation(string.Empty, firstColumns, secondColumns, false);
ds.Relations.Add(r1);
DataRelation r2 = new DataRelation(string.Empty, secondColumns, firstColumns, false);
ds.Relations.Add(r2);
//Create columns for return table
for (int i = 0; i < FirstDataTable.Columns.Count; i++)
{
ResultDataTable.Columns.Add(FirstDataTable.Columns[i].ColumnName, FirstDataTable.Columns[i].DataType);
}
//If FirstDataTable Row not in SecondDataTable, Add to ResultDataTable.
ResultDataTable.BeginLoadData();
foreach (DataRow parentrow in ds.Tables[0].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r1);
if (childrows == null || childrows.Length == 0)
ResultDataTable.LoadDataRow(parentrow.ItemArray, true);
}
//If SecondDataTable Row not in FirstDataTable, Add to ResultDataTable.
foreach (DataRow parentrow in ds.Tables[1].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r2);
if (childrows == null || childrows.Length == 0)
ResultDataTable.LoadDataRow(parentrow.ItemArray, true);
}
ResultDataTable.EndLoadData();
}
return ResultDataTable;
}
#endregion
private void ExportDataTableToExcel(DataTable dt, string strFilePath)
{
// Create the CSV file to which grid data will be exported.
StreamWriter sw = new StreamWriter(strFilePath, false);
// First we will write the headers.
//DataTable dt = m_dsProducts.Tables[0];
int iColCount = dt.Columns.Count;
for (int i = 0; i < iColCount; i++)
{
sw.Write(dt.Columns[i]);
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
// Now write all the rows.
foreach (DataRow dr in dt.Rows)
{
for (int i = 0; i < iColCount; i++)
{
if (!Convert.IsDBNull(dr[i]))
{
sw.Write(dr[i].ToString());
}
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
}
sw.Close();
}
#endregion
}
private void button1_Click(object sender, EventArgs e)
{
//Declare the class and set the excel file dir/path and sheet name
ExcelHandler eh = new ExcelHandler() { Directory = "c:\\temp", FirstFile = "Book1.xlsx", FirstFileSheetName = "Sheet1", SecondFile = "Book2.xlsx", SecondFileSheetName = "Sheet1" };
//Get the datatable
DataTable dt = eh.CheckExcelFiles();
//Or write to CSV top open with excel
eh.CheckExcelFiles("c:\\temp\\test123.csv");
}
this works for me only that it is merging the content of the two worksheet into a new excel sheet test123.csv, i want to show only the difference, i will appreciate, if anyone could assist. Thanks in advance
This question already has answers here:
Reading CSV file and storing values into an array
(21 answers)
Closed 8 years ago.
I am a learner in C#. I want to read a particular value from the CSV file. I have learned the getting the csv file into a datatable through browsing. Please see the following code (Thanks to surendra jha) and my CSV file format. Say, I want to get what is the 'Volume' for 'ID' = 90.
CSV file
ID:Volume:Name
100:5600:A
95:5000:B
90:4500:C
85:4000:D
Code for getting all the values:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
namespace DVHConsolePrj
{
class Program
{
static void Main(string[] args)
{
readCsvFileData();
}
static void readCsvFileData()
{
string path = #"C:\IDVolumeName.txt";
StreamReader streamreader = new StreamReader(path);
DataTable datatable = new DataTable();
int rowcount = 0;
string[] columnname = null;
string[] streamdatavalue = null;
while (!streamreader.EndOfStream)
{
string streamrowdata = streamreader.ReadLine().Trim();
if (streamrowdata.Length > 0)
{
streamdatavalue = streamrowdata.Split(':');
if (rowcount == 0)
{
rowcount = 1;
columnname = streamdatavalue;
foreach (string csvheader in columnname)
{
DataColumn datacolumn = new DataColumn(csvheader.ToUpper(), typeof(string));
datacolumn.DefaultValue = string.Empty;
datatable.Columns.Add(datacolumn);
}
}
else
{
DataRow datarow = datatable.NewRow();
for (int i = 0; i < columnname.Length; i++)
{
datarow[columnname[i]] = streamdatavalue[i] == null ? string.Empty : streamdatavalue[i].ToString();
}
datatable.Rows.Add(datarow);
}
}
}
streamreader.Close();
streamreader.Dispose();
foreach (DataRow dr in datatable.Rows)
{
string rowvalues = string.Empty;
foreach (string csvcolumns in columnname)
{
rowvalues += csvcolumns + "=" + dr[csvcolumns].ToString() + " ";
}
Console.WriteLine(rowvalues);
}
Console.ReadLine();
}
}
}
Instead of parsing the file manually in a DataTable, then doing some Linq, use Linq directly on it, using this library.
It works pretty well and is very efficient with big files.
For instance.
1) Add nuget package in your project, and the following line to be able to use it:
using LINQtoCSV;
2) define the class that olds the data
public class IdVolumeNameRow
{
[CsvColumn(FieldIndex = 1)]
public string ID { get; set; }
[CsvColumn(FieldIndex = 2)]
public decimal Volume { get; set; }
[CsvColumn(FieldIndex = 3)]
public string Name{ get; set; }
}
3) and search for the value
var csvAttributes = new CsvFileDescription
{
SeparatorChar = ':',
FirstLineHasColumnNames = true
};
var cc = new CsvContext();
var volume = cc.Read<IdVolumeNameRow>(#"C:\IDVolumeName.txt", csvAttributes)
.Where(i => i.ID == "90")
.Select(i => i.Volume)
.FirstOrDefault();
public DataTable CSVToDataTable(string filename, string separator)
{
try
{
FileInfo file = new FileInfo(filename);
OleDbConnection con =
new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"" +
file.DirectoryName + "\";
Extended Properties='text;HDR=Yes;FMT=Delimited(" + separator + ")';")
OleDbCommand cmd = new OleDbCommand(string.Format
("SELECT * FROM [{0}]", file.Name), con);
con.Open();
DataTable tbl = new DataTable();
using (OleDbDataAdapter adp = new OleDbDataAdapter(cmd))
{
tbl = new DataTable("MyTable");
adp.Fill(tbl);
}
return tbl;
}
catch(Exception ex)
{
throw ex;
}
finally()
{
con.Close();
}
}
You can try this code, it is build on the fly, it is possible little errors to exist. Check OleDbConnection. When you return the DataTable you can search in the table using LINQ.
var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<int>("ID") == 90
select myRow;
Here you can take the row with ID=90 !
For filtering DataTable you can use DataTable.Select method like this
var filtered = dataTable.Select("ID = '90'");
filtered above is array of datarow that suitable for the condition, so for get value from first filtered row you can use something like
if(filtered.Length>0){
var Volume = filtered[0]["VOLUME"];
}
Is there an easy way to tell EPPlus that a row is a header? Or should I create the headers by specifying a range using SelectedRange, remove it from the sheet and iterate the cells that remain?
I ended up doing this:
class Program
{
static void Main(string[] args)
{
DirectoryInfo outputDir = new DirectoryInfo(#"C:\testdump\excelimports");
FileInfo existingFile = new FileInfo(outputDir.FullName + #"\Stormers.xlsx");
Dictionary<string, string> arrColumnNames = new Dictionary<string,string>() { { "First Name", "" }, { "Last Name", "" }, { "Email Address", "" } };
using (ExcelPackage package = new ExcelPackage(existingFile))
{
ExcelWorksheet sheet = package.Workbook.Worksheets[1];
var q = from cell in sheet.Cells
where arrColumnNames.ContainsKey(cell.Value.ToString())
select cell;
foreach (var c in q)
{
arrColumnNames[c.Value.ToString()] = c.Address;
}
foreach (var ck in arrColumnNames)
{
Console.WriteLine("{0} - {1}", ck.Key, ck.Value);
}
var qValues = from r in sheet.Cells
where !arrColumnNames.ContainsValue(r.Address.ToString())
select r;
foreach (var r in qValues)
{
Console.WriteLine("{0} - {1}", r.Address, r.Value);
}
}
}
}
I needed to enumerate through header and display all the columns headers to my end user. I took Muhammad Mubashir code as base and changed/converted it to extension method and removed hard-coded numbers from it.
public static class ExcelWorksheetExtension
{
public static string[] GetHeaderColumns(this ExcelWorksheet sheet)
{
List<string> columnNames = new List<string>();
foreach (var firstRowCell in sheet.Cells[sheet.Dimension.Start.Row, sheet.Dimension.Start.Column, 1, sheet.Dimension.End.Column])
columnNames.Add(firstRowCell.Text);
return columnNames.ToArray();
}
}
var pck = new OfficeOpenXml.ExcelPackage();
pck.Load(new System.IO.FileInfo(path).OpenRead());
var ws = pck.Workbook.Worksheets["Worksheet1"];
DataTable tbl = new DataTable();
var hasHeader = true;
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);
}
I had a similar issue. Here's some code that may help:
using (var package = new ExcelPackage(fileStream))
{
// Get the workbook in the file
var workbook = package.Workbook;
if (workbook != null && workbook.Worksheets.Any())
{
// Get the first worksheet
var sheet = workbook.Worksheets.First();
// Get header values
var column1Header = sheet.Cells["A1"].GetValue<string>();
var column2Header = sheet.Cells["B1"].GetValue<string>();
// "A2:A" means "starting from A2 (1st col, 2nd row),
// get me all populated cells in Column A" (yes, unusual range syntax)
var firstColumnRows = sheet.Cells["A2:A"];
// Loop through rows in the first column, get values based on offset
foreach (var cell in firstColumnRows)
{
var column1CellValue = cell.GetValue<string>();
var column2CellValue = cell.Offset(0, 1).GetValue<string>();
}
}
}
If anyone knows of a more elegant way than cell.Offset, let me know.
I just took ndd code and convert it with using of System Linq.
using System.Linq;
using OfficeOpenXml;
namespace Project.Extensions.Excel
{
public static class ExcelWorksheetExtension
{
/// <summary>
/// Get Header row with EPPlus.
/// <a href="https://stackoverflow.com/questions/10278101/epplus-reading-column-headers">
/// EPPlus Reading Column Headers
/// </a>
/// </summary>
/// <param name="sheet"></param>
/// <returns>Array of headers</returns>
public static string[] GetHeaderColumns(this ExcelWorksheet sheet)
{
return sheet.Cells[sheet.Dimension.Start.Row, sheet.Dimension.Start.Column, 1, sheet.Dimension.End.Column]
.Select(firstRowCell => firstRowCell.Text).ToArray();
}
}
}