I am using EPPlus library in my .net core web api. In the said method I want to validate he uploaded excel. I want to find out if my entire row is empty. I have the following code:
using (ExcelPackage package = new ExcelPackage(file.OpenReadStream()))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int rowCount = worksheet.Dimension.End.Row;
int colCount = worksheet.Dimension.End.Column;
//loop through rows and columns
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= ColCount; col++)
{
var rowValue = worksheet.Cells[row, col].Value;
//Want to find here if the entire row is empty
}
}
}
rowValue above would give me if the particular cell if empty or not. Is it possible to check for the entire row and proceed to next row if empty.
you can check the row cell range value with linq:
var startRow = 1;
var endRow = 1;
var columnStart = 1;
var columnEnd = worksheet.Cells.End.Column;
var cellRange = worksheet.Cells[startRow, columnStart , endRow, columnEnd];
var isRowEmpty = cellRange.All(c => c.Value == null)
If you do not know the number of columns to check you can take advantage of the fact that the Worksheet.Cells collection only contains entries for cells that actually have values:
[TestMethod]
public void EmptyRowsTest()
{
//Throw in some data
var datatable = new DataTable("tblData");
datatable.Columns.AddRange(new[] { new DataColumn("Col1", typeof(int)), new DataColumn("Col2", typeof(int)), new DataColumn("Col3", typeof(object)) });
//Only fille every other row
for (var i = 0; i < 10; i++)
{
var row = datatable.NewRow();
if (i % 2 > 0)
{
row[0] = i;
row[1] = i * 10;
row[2] = Path.GetRandomFileName();
}
datatable.Rows.Add(row);
}
//Create a test file
var existingFile = new FileInfo(#"c:\temp\EmptyRowsTest.xlsx");
if (existingFile.Exists)
existingFile.Delete();
using (var pck = new ExcelPackage(existingFile))
{
var worksheet = pck.Workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromDataTable(datatable, true);
pck.Save();
}
//Load from file
using (var pck = new ExcelPackage(existingFile))
{
var worksheet = pck.Workbook.Worksheets["Sheet1"];
//Cells only contains references to cells with actual data
var cells = worksheet.Cells;
var rowIndicies = cells
.Select(c => c.Start.Row)
.Distinct()
.ToList();
//Skip the header row which was added by LoadFromDataTable
for (var i = 1; i <= 10; i++)
Console.WriteLine($"Row {i} is empty: {rowIndicies.Contains(i)}");
}
}
Gives this in the output (Row 0 is the column headers):
Row 1 is empty: True
Row 2 is empty: False
Row 3 is empty: True
Row 4 is empty: False
Row 5 is empty: True
Row 6 is empty: False
Row 7 is empty: True
Row 8 is empty: False
Row 9 is empty: True
Row 10 is empty: False
You can set a bool in the for loop at row level. Then loop all the cells and change the bool when a cell is not empty.
//loop through rows and columns
for (int row = 1; row <= rowCount; row++)
{
//create a bool
bool RowIsEmpty = true;
for (int col = 1; col <= colCount; col++)
{
//check if the cell is empty or not
if (worksheet.Cells[row, col].Value != null)
{
RowIsEmpty = false;
}
}
//display result
if (RowIsEmpty)
{
Label1.Text += "Row " + row + " is empty.<br>";
}
}
You can use the worksheet.Cells[row, col].count() method for this.
If the row is empty then this method will return 0.
Related
I have an excel file which has say 5 columns and 5 rows.
I am using EPPlus (.net core c#)to parse the contents of the file.
I have the below code to count the rows and columns and then parse contents of this excel file.
using (ExcelPackage package = new ExcelPackage(stream))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int rowCount = worksheet.Dimension.End.Row;
int colCount = worksheet.Dimension.End.Column;
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= colCount; col++)
{
//Parse here
}
}
}
With 5 rows and 5 columns of data as mentioned this works fine.
If I update and save the same file, and delete say 3 rows and 3 columns.
Now if I read this file again it still shows 5 columns and rows. Not sure if there is another way to read actual rows and columns?
Am I missing something here.
Try this
using (ExcelPackage package = new ExcelPackage(stream))
{
string directoryServerPath = // your file saving path in server;
if (!Directory.Exists(directoryServerPath))
Directory.CreateDirectory(directoryServerPath);
System.IO.DirectoryInfo directoryFiles = new DirectoryInfo(directoryServerPath);
foreach (FileInfo file in directoryFiles.GetFiles())
{
file.IsReadOnly = false;
file.Delete();
}
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int rowCount = worksheet.Dimension.Rows;
int colCount = worksheet.Dimension.Columns;
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= colCount; col++)
{
//Parse here
}
}
package.SaveAs(new System.IO.FileInfo(directoryServerPath + fileName));
System.IO.File.SetAttributes(directoryServerPath + fileName, FileAttributes.ReadOnly);
}
I have a listbox and I manage to bind the Excel worksheet to the list box (after hours of researching on the Internet).
Now I need to read the values from the sheet into the listbox, but unable to locate any suitable solution.
This is what I have done so far:-
private void LoadExcelSheet(string path, int sheet){
_Application excel = new Excel.Application();
Workbook wb;
Worksheet ws;
int row = 0;
int col = 0;
wb = excel.Workbooks.Open(path);
ws = wb.Worksheets[sheet];
for (row = 1; row < 10; row++){
for (col = 1; col < 6; col++){
listBox1.Items.Add(ws.Cells[row, col].Value2);
}
}
}
//------------------ end of LoadExcelSheet---------------------------
this only display 1 row with each item of data on top of each other eg:-
aaaaaaaa
bbbbbbbb
cccccccc
dddddddd
instead of: aaaaaaaa bbbbbbbb cccccccc dddddddd
Thanks in advance..
The issue is with your for loops, try this:
for (var row = 1; row < 10; row++)
{
string r = "";
for (var col = 1; col < 6; col++)
{
r += " " + ws.Cells[row, col].Value2;
}
listBox1.Items.Add(r.Trim());
}
You are populating the list box inside a loop containing the columns, try something like
for (row = 1; row < 10; row++){
string a = "";
for (col = 1; col < 6; col++){
a += ws.Cells[row, col].Value2+" ";
}
listBox1.Items.Add(a);
}
Let's split the problem
Data collection
Collected data representation
Data collection (with a help of Linq):
using System.Linq;
...
string[] data = Enumerable
.Range(1, 9) // 9 rows, starting from 1
.Select(row => string.Join(" ", Enumerable // cols are joined with space
.Range(1, 5) // 5 columns in each row
.Select(col => ws.Cells[row, col].Value2)))
.ToArray();
And data representation (as ListBox items):
listBox1.Items.AddRange(data);
I have a data table that I am creating from an excel file. This works fine. But, I recently had a spec change and need to substitute a value in column 0 of the table. I am having trouble getting my IF statement to fire. It is probably something simple I am overlooking.
Basically, if it is the first column in the row, I want to put a specific value I pulled elsewhere (I am pulling the color of the cell and putting in the RGB value). If it is any other column in the row, continue to read in the data as usual.
Please see the below code:
DataTable tbl = new DataTable();
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 cellColor = ws.Cells[firstRowCell].Style.Fill.BackgroundColor.LookupColor();
}
//var startRow = hasHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var currentRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.Rows.Add();
for (var i = 0; i < tbl.Columns.Count; i++)
{
//This is my problem. I am not seeing what needs to be in here.
if (tbl.Columns.????????)
{
row[i] = colorTable[rowNum];
}
else
{
row[i] = currentRow[rowNum, i + 1].Text;
}
}
}
You're in a for loop that starts at your first column to the last
for (var i = 0; i < tbl.Columns.Count; i++)
So the value you can use to know at what column you're at would be the i, you could have something like this
for (var i = 0; i < tbl.Columns.Count; i++)
{
//If you're at the first column
if (i == 0)
{
row[i] = colorTable[rowNum];
}
else
{
row[i] = currentRow[rowNum, i + 1].Text;
}
}
I wanna show all my DataSource rows on a DataGridView, but not as rows but as columns of a row. Each 12 items retrieved, I wanna insert a new row on the DataGridView and populate this new row with more items from the DataSource (12 at each row).
My DataSource retrieves just one item each, and using it directly with the DataGridView is working nicely, but shown a different row for each item.
Any hints?
Thanks to #SriramSakthivel.
private void AddToList(DataTable dt)
{
possibleWords = 0;
// Cleans the data grid view
WordList.DataSource = null;
WordList.Refresh();
// Let's transform the original data table onto another, changing rows by columns
DataTable table = new DataTable();
for (int i = 0; i < 10; i++)
{
table.Columns.Add(Convert.ToString(i));
}
DataRow r;
int col = 0;
//for (int k = 0; k < dt.Columns.Count; k++)
{
r = table.NewRow();
for (int j = 0; j < dt.Rows.Count; j++)
{
if (col >= 10)
{
table.Rows.Add(r);
col = 0;
r = table.NewRow();
}
r[col++] = (dt.Rows[j][0]).ToString().ToUpper();
possibleWords++;
}
table.Rows.Add(r);
}
// Puts the new data table as datasource of the word list
DataView dv = table.DefaultView;
WordList.DataSource = dv;
if (possibleWords == 0)
return;
WordList.Columns[0].DefaultCellStyle.BackColor = Color.WhiteSmoke;
WordList.ColumnHeadersVisible = false;
WordList.RowHeadersVisible = false;
}
I have datatable and I am displaying those values in the datagridview with the helping of code :
dataGridView1.ColumnCount = TableWithOnlyFixedColumns.Columns.Count;
dataGridView1.RowCount = TableWithOnlyFixedColumns.Rows.Count;
for (int i = 0; i < dataGridView1.RowCount; i++)
{
for (int j = 0; j < dataGridView1.ColumnCount; j++)
{
dataGridView1[j, i].Value = TableWithOnlyFixedColumns.Rows[i][j].ToString();
}
}
TableExtractedFromFile.Clear();
TableWithOnlyFixedColumns.Clear();
Now I want to save the records in the datatable in csv file.How can I do that ?
You could do this:
// we'll use these to check for rows with nulls
var columns = yourTable.Columns
.Cast<DataColumn>();
// say the column you want to sort by is called "Date"
var rows = yourTable.Select("", "Date ASC"); // or "Date DESC"
using (var writer = new StreamWriter(yourPath)) {
for (int i = 0; i < rows.Length; i++) {
DataRow row = rows[i];
// check for any null cells
if (columns.Any(column => row.IsNull(column)))
continue;
string[] textCells = row.ItemArray
.Select(cell => cell.ToString()) // may need to pick a text qualifier here
.ToArray();
// check for non-null but EMPTY cells
if (textCells.Any(text => string.IsNullOrEmpty(text)))
continue;
writer.WriteLine(string.Join(",", textCells));
}
}