C# - How do I iterate all the rows in Excel._Worksheet? - c#

I am looking to programmatically pull data from an Excel worksheet and insert it into a database table.
How do I determine the number of columns and rows in a worksheet or otherwise iterate the rows?
I have
Excel._Worksheet worksheet = (Excel._Worksheet)workbook.ActiveSheet;
I tried worksheet.Range.Rows.Count
which tosses up
Indexed property 'Microsoft.Office.Interop.Excel._Worksheet.Range' has
non-optional arguments which must be provided
What needs to be done?

using Excel = Microsoft.Office.Interop.Excel;
...
public void IterateRows(Excel.Worksheet worksheet)
{
//Get the used Range
Excel.Range usedRange = worksheet.UsedRange;
//Iterate the rows in the used range
foreach(Excel.Range row in usedRange.Rows)
{
//Do something with the row.
//Ex. Iterate through the row's data and put in a string array
String[] rowData = new String[row.Columns.Count];
for(int i = 0; i < row.Columns.Count; i++)
rowData[i] =Convert.ToString(row.Cells[1, i + 1].Value2);
}
}
This compiles and runs just great for me! I'm using it to extract rows with missing fields to an error log.

I presume you are actually looking for the last used row. In that case you need to write it like this:
Range UsedRange = worksheet.UsedRange;
int lastUsedRow = UsedRange.Row + UsedRange.Rows.Count - 1;

Related

Copying specific range of excel cells from below a specific keyword

I am wanting to write a C# program to copy a specific range of cells below a specific keyword. The code will identify a keyword in Excel and then copy the values of all the cells below the keyword to copy into another range.
I am using Aspose. I attempted to write code to find the keyword and can successfully return the cell the keyword is located in. What I am trying to figure out how to do is copy the range specifically below any keyword into another range. I can successfully copy one range to another range but cannot do it from below a specific keyword.
Cells cellsOne = worksheet.Cells;
FindOptions findOptions = new FindOptions();
findOptions.LookAtType = LookAtType.StartWith;
Cell cell = cellsOne.Find("Accounting", null, findOptions);
//Printing the name of the cell found after searching worksheet
Console.WriteLine("Name of the cell containing String: " + cell.Name);
//if cell is found/value is returned
if (cell.Name.Contains("Accounting"))
{
//return cell value ?
//copy all below values (will need the cell keyword is in to do that)
//paste below values into specific columns
//doing it manually
Aspose.Cells.Range range1 = cellsOne.CreateRange("A2:A10");
Aspose.Cells.Range range2 = cellsOne.CreateRange("B28:B34");
range1.Copy(range2);
}
I have visited Aspose website but am struggling to copy a range BELOW a specific keyword. Thank you.
I don't know how to do it in C#, but I would advise you to find the cell which has the value, then in your "Range" statement below you could start at that cell you found before.
For example,
Cell cell = cellsOne.Find("Accounting", null, findOptions).Row;
You get for example "320", then your next line goes to that 320. Using your code:
Aspose.Cells.Range range1 = cellsOne.CreateRange("A2:A10");
Aspose.Cells.Range range2 = cellsOne.CreateRange("B" & cell & ":B34");
range1.Copy(range2);`
That's what I would do in VBA.
Hope it helps!
Checking your code segment a bit, I thought your destination range is "A2:A10". Your code needs some tweaks. See the updated (complete) sample code with comments to accomplish your task for your reference. I evaluated the source range (below the searched keyword) dynamically using CellsHelper static class.
e.g.
Sample code:
Workbook workbook = new Workbook("e:\\test2\\Book1.xlsx");
Worksheet worksheet = workbook.Worksheets[0];
Cells cellsOne = worksheet.Cells;
FindOptions findOptions = new FindOptions();
findOptions.LookAtType = LookAtType.StartWith;
Cell cell = cellsOne.Find("Accounting", null, findOptions);
//Printing the name of the cell found after searching worksheet
Console.WriteLine("Name of the cell containing String: " + cell.Name);
//if cell is found/value is returned
if (cell != null)
{
//I thought this is your destination range
Aspose.Cells.Range range1 = cellsOne.CreateRange("A2:A10");
//Evaluate the the next cell after (found) cell's row and column indices.
int startRow = cell.Row +1; //we add "1" to get the next in the same column
int startCol = cell.Column;
string startCell = CellsHelper.CellIndexToName(startRow, startCol);
//Set and evaluate your end cell for the range.
string endCell = CellsHelper.CellIndexToName(startRow + 6, startCol);
//Create your dynamic source range based on your startCell and endCell values
Aspose.Cells.Range range2 = cellsOne.CreateRange(startCell, endCell);
//Copy the source range to destination range
range1.Copy(range2);
}
workbook.Save("e:\\test2\\out1.xlsx");
Hope, this helps a bit.
You may also see the document on copying ranges for your further reference.
PS. I am working as Support developer/ Evangelist at Aspose.

Finding the last used cell on worksheet and copying row into another worksheet?

any answere would be very much appreciated.
My question is as follow:
Is this the correct way to determin the last non-empty cell/row of my excel worksheet?
xl.Worksheet sh;
int lastRow;
int fullRow;
sh = xlApp.Workbooks.get_Item("myExcelFile").Worksheets.get_Item("MySheet");
fullRow = sh.Rows.Count;
lastRow = sh.Cells[fullRow, 1].End(xl.XlDirection.xlUp).Row;
And if this is indeed correct how do I take my row and copy it into another worksheet. To be more specifict, the first empty cell of column A.
I know that i must use a command that is something like this:
lastRow.EntireRow.Copy(FirstEmptyCell);
Being a int type i cannot copy it to my other sheet.
Any suggestions?
lastRow = sh.Cells[fullRow, 1].End(xl.XlDirection.xlUp).Row;
here, lastRow is an int so you can't use it as an object on your next line:
lastRow.EntireRow.Copy(FirstEmptyCell); // int doesn't have an EntireRow property
What you can do is combine the two into a single line:
Excel.Range myLastRow;
myLastRow = sh.Cells[sh.Rows.Count, 1].End(xl.xlDirection.Up).EntireRow;
now myLastRow is the entire row that you want to copy.
myLastRow.Copy(destination);

How to get all the rows which contain data in a particular column in Excel from C#

I have a data set in Excel and am using C# to open the worksheet and access some of the data.
I am trying to get all the rows that contain data from a particular column. For example in column B starting from cell 'B3' going down I want to store all the rows that contain data in a collection like an Array.
This is what I have so far:
Application excelApplication;
_Workbook workbook;
_Worksheet sheet;
excelApplication = new Excel.Application
{
Visible = true,
ScreenUpdating = true
};
workbook = excelApplication.Workbooks.Open(#"C:\Documents and Settings\user\Desktop\Book1.xls");
sheet = (Worksheet)workbook.Worksheets[2];
Excel.Range range = sheet.Range["b3:b145"].
foreach (Range cell in range)
{
// Do something with rows which contain data
}
As you can see above I have specified the range from B3 to B45 which I don't want. I want to get all the rows in the B column which contain data starting from B3.
How would I achieve this?
In general when I get stuck in these situations I record a Macro and convert the VBA code to C#. The object model in VSTO is pretty much exactly the same (remember this its a great tip) and with .Net 4.0 onwards optional parameters save a lot of code.
In your particular instance I envisage the larger the spreadsheet the longer it will take to read all the Excel cells in column B using VSTO. My advice is to use this technique to read them all at once:
//Work out the number of rows with data in column B:
//int lastColumn = range.Columns.Count;
int lastRow = range.Rows.Count;
//Get all the column values:
object[,] objectArray = shtName.get_Range("B3:B" + lastRow.ToString()).Value2;
rngName.Value2 = objectArray;

How to create Excel file from List<string> using Microsoft.Office.Interop.Excel

I've a List with some values, I've also a TextBox where I must write a number, then I need to build a Excel with many Sheets with values coming from List. In other words and for example: List have 1000 values, then I enter 100 in TextBox, so I'll need to generate a Excel file with many sheets as values are in List iterating over the value entered in the TextBox in this case will be one Excel file with 10 sheets, every sheet with 100 cells. It's clear? How I can do this using Microsoft.Office.Interop.Excel?
For worksheets:
//get the first workbook in an application
Workbook WB = Application.Workbooks[0]; //Or any other workbook you preffer
Now loop the following for each list of strings you have (each list to a worksheet)
Worksheet WS = (Worksheet)WB.Worksheets.Add(); //this command adds worksheets
Range R = WS.Range["A1"]; //or any other cell you like
//now for cells
for (int i = 0; i < YourStringList.Count; i++) //I believe you can manage to separate the lists yourself
{
R.Offset[i, 0].Value = YourStringList[i];
}
End of the loop

Programmatically getting the last filled excel row using C#

I am trying to get the last row of an excel sheet programatically using the Microsoft.interop.Excel Library and C#. I want to do that, because I am charged with looping through all the records of an excel spreadsheet and performing some kind of operation on them. Specifically, I need the actual number of the last row, as I will throw this number into a function. Anybody have any idea how to do that?
Couple ways,
using Excel = Microsoft.Office.Interop.Excel;
Excel.ApplicationClass excel = new Excel.ApplicationClass();
Excel.Application app = excel.Application;
Excel.Range all = app.get_Range("A1:H10", Type.Missing);
OR
Excel.Range last = sheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Excel.Range range = sheet.get_Range("A1", last);
int lastUsedRow = last.Row;
int lastUsedColumn = last.Column;
This is a common issue in Excel.
Here is some C# code:
// Find the last real row
nInLastRow = oSheet.Cells.Find("*",System.Reflection.Missing.Value,
System.Reflection.Missing.Value, System.Reflection.Missing.Value, Excel.XlSearchOrder.xlByRows,Excel.XlSearchDirection.xlPrevious, false,System.Reflection.Missing.Value,System.Reflection.Missing.Value).Row;
// Find the last real column
nInLastCol = oSheet.Cells.Find("*", System.Reflection.Missing.Value, System.Reflection.Missing.Value,System.Reflection.Missing.Value, Excel.XlSearchOrder.xlByColumns,Excel.XlSearchDirection.xlPrevious, false,System.Reflection.Missing.Value,System.Reflection.Missing.Value).Column;
found here
or using SpecialCells
Excel.Range last = sheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Excel.Range range = sheet.get_Range("A1", last);
[EDIT] Similar threads:
VB.NET - Reading ENTIRE content of an excel file
How to get the range of occupied cells in excel sheet
Pryank's answer is what worked closest for me. I added a little bit towards the end (.Row) so I am not just returning a range, but an integer.
int lastRow = wkSheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing).Row;
The only way I could get it to work in ALL scenarios (except Protected sheets):
It supports:
Scanning Hidden Row / Columns
Ignores formatted cells with no data / formula
Code:
// Unhide All Cells and clear formats
sheet.Columns.ClearFormats();
sheet.Rows.ClearFormats();
// Detect Last used Row - Ignore cells that contains formulas that result in blank values
int lastRowIgnoreFormulas = sheet.Cells.Find(
"*",
System.Reflection.Missing.Value,
InteropExcel.XlFindLookIn.xlValues,
InteropExcel.XlLookAt.xlWhole,
InteropExcel.XlSearchOrder.xlByRows,
InteropExcel.XlSearchDirection.xlPrevious,
false,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value).Row;
// Detect Last Used Column - Ignore cells that contains formulas that result in blank values
int lastColIgnoreFormulas = sheet.Cells.Find(
"*",
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
InteropExcel.XlSearchOrder.xlByColumns,
InteropExcel.XlSearchDirection.xlPrevious,
false,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value).Column;
// Detect Last used Row / Column - Including cells that contains formulas that result in blank values
int lastColIncludeFormulas = sheet.UsedRange.Columns.Count;
int lastColIncludeFormulas = sheet.UsedRange.Rows.Count;
For questions involving the Excel object model, it's often easier to try it out in VBA first, then translating to C# is fairly trivial.
In this case one way to do it in VBA is:
Worksheet.UsedRange.Row + Worksheet.UsedRange.Rows.Count - 1
The ActiveSheet.UsedRange.Value returns a 2 dimensional object array of [row, column]. Checking the length of both dimensions will provide the LastRow index and the LastColumn index. The example below is using C#.
Excel.Worksheet activeSheet;
Excel.Range activeRange;
public virtual object[,] RangeArray
{
get { return ActiveRange.Value; }
}
public virtual int ColumnCount
{
get { return RangeArray.GetLength(1); }
}
public virtual int RowCount
{
get { return RangeArray.GetLength(0); }
}
public virtual int LastRow
{
get { return RowCount; }
}
This issue is even worse when there are possibly empty cells. But you have to read a row even if only one value is filled. It can take a while when there are a lot of unfilled cells but if the input is close to correct it is rather fast.
My solution ignores completely empty rows and returns the longest column's row count:
private static int GetLastRow(Worksheet worksheet)
{
int lastUsedRow = 1;
Range range = worksheet.UsedRange;
for (int i = 1; i < range.Columns.Count; i++)
{
int lastRow = range.Rows.Count;
for (int j = range.Rows.Count; j > 0; j--)
{
if (lastUsedRow < lastRow)
{
lastRow = j;
if (!String.IsNullOrWhiteSpace(Convert.ToString((worksheet.Cells[j, i] as Range).Value)))
{
if (lastUsedRow < lastRow)
lastUsedRow = lastRow;
if (lastUsedRow == range.Rows.Count)
return lastUsedRow - 1;
break;
}
}
else
break;
}
}
return lastUsedRow;
}
For those who use SpecialCells method, (I'm not sure about others), Please Note in case your last cell is merged, you won't be able to get last row and column number using Range.Row and Range.Column to get the last row and column as numbers.
you need to first Unmerge your range and then Again get the last cell.
It cost me a lot.
private int[] GetLastRowCol(Ex.Worksheet ws)
{
Ex.Range last = ws.Cells.SpecialCells(Ex.XlCellType.xlCellTypeLastCell, Type.Missing);
bool isMerged = (bool)last.MergeCells;
if (isMerged)
{
last.UnMerge();
last = ws.Cells.SpecialCells(Ex.XlCellType.xlCellTypeLastCell, Type.Missing);
}
return new int[2] { last.Row, last.Column };
}
As previously discussed, the techniques above (xlCellTypeLastCell etc.) do not always provide expected results. Although it's not difficult to iterate down through a column checking for values, sometimes you may find that there are empty cells or rows with data that you want to consider in subsequent rows. When using Excel directly, a good way of finding the last row is to press CTRL + Down Arrow a couple of times (you'll end up at row 1048576 for an XLSX worksheet) and then press CTRL + Up Arrow which will select the last populated cell. If you do this within Excel while recording a Macro you'll get the code to replicate this, and then it's just a case of tweaking it for C# using the Microsoft.Office.Interop.Excel libraries. For example:
private int GetLastRow()
{
Excel.Application ExcelApp;
ExcelApp = new Excel.Application();
ExcelApp.Selection.End(Excel.XlDirection.xlDown).Select();
ExcelApp.Selection.End(Excel.XlDirection.xlDown).Select();
ExcelApp.Selection.End(Excel.XlDirection.xlDown).Select();
ExcelApp.Selection.End(Excel.XlDirection.xlUp).Select();
return ExcelApp.ActiveCell.Row;
}
It may not be the most elegant solution (I guess instead you could navigate to the final row within the spreadsheet first directly before using XlUp) but it seems to be more reliable.
As CtrlDot and Leo Guardian says, it is not very acuarate the method, there some files where formats affect the "SpecialCells".
So I used a combination of that plus a While.
Range last = sheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);
Range range = sheet.get_Range("A1", last);
int lastrow = last.Row;
// Complement to confirm that the last row is the last
string textCell= "Existe";
while (textCell != null)
{
lastrow++;
textCell = sheet.Cells[lastrow + 1, 1].Value;
}
In case of using OfficeOpenXml nowadays:
using OfficeOpenXml;
using System.IO;
FileInfo excelFile = new FileInfo(filename);
ExcelPackage package = new ExcelPackage(excelFile);
ExcelWorksheet sheet = package.Workbook.Worksheets[1];
int lastRow = sheet.Dimension.End.Row;
int lastColumn = sheet.Dimension.End.Column;
I don't know if using Microsoft.Office.Interop.Excel is still state of the art or more a legacy library. In my opinion I'm doing well replacing with OfficeOpenXml. So this answer might be usefull for future search results.

Categories

Resources