I've populated an excel file starting with column 14. The important rows are from 2 to 30 let's say.
valueArray = (object[,])excelRange.get_Value(Excel.XlRangeValueDataType.xlRangeValueDefault);
I am using get_Value to get all the values on rows and columns. The problem appears when it changes my columns from 14th to 1, 15th to 2 and so on. So if i am going to iterate with
valueArray[row, column]
searching for the row 2 and column 14, row 3 and column 14 and so on, i will get an error because the valueArray has a different interpretation of columns.
Is there any way to get fixed positions from the excel sheet?
The simlest way is to apply an offset when iterating with valueArray:
for (int row = 2; row <= 30; row++)
{
for (int column = 14; column <= 100500; column++)
{
object value = valueArray[row - 2, column - 14];
}
}
otherwise you could use an another data structure:
Dictionary<Point, Object> valueArray = new Dictionary<Point, Object>();
valueArray[new Point(2, 14)] = (worksheet.Cells[2, 14] as Excel.Range).Value; // Add values in this way
Object value = valueArray[new Point(2, 14)]; // Read values
Related
I'm using the following code to parse the XLS file using ExcelDataReader. I would like to exclude the first three rows, first two columns followed by any columns that are after 9.
//create the reader
var reader = ExcelReaderFactory.CreateReader(stream);
var result = reader.AsDataSet();
//remove the first 3 rows
DataRowCollection dt = result.Tables[0].Rows;
dt.RemoveAt(0);
dt.RemoveAt(1);
dt.RemoveAt(2);
//exclude the column 1 and2 and any columns after 9
for (int columnNumber = 2; columnNumber < 8; columnNumber++)
{
foreach (DataRow dr in dt)
{
Debug.Log(dr[columnNumber].ToString());
msg += dr[columnNumber].ToString();
}
}
Unfortunately, it does not skip the rows and columns as expected. How do I skip specific columns and rows using excelDataReader?
You are doing the following
dt.RemoveAt(0);
dt.RemoveAt(1);
dt.RemoveAt(2);
When the first line executes, the rows are reindexed with the 1 becoming 0, 2 becoming 1 and so on.
When the second line executes you have now removed the line that was position 2 originally. The rows are again reindexed.
When the third line executes you are then again removing an incorrect row.
As a result, when this process completes, it will have removed the lines that were originally positioned at 0, 2, and 4.
Change the code to remove the correct lines, or skip three lines with linq or a for loop.
Sample using for loop (not tested).
//create the reader
var reader = ExcelReaderFactory.CreateReader(stream);
var result = reader.AsDataSet();
DataRowCollection dt = result.Tables[0].Rows;
//ignore the first 3 rows
for(int dataRowCount = 3; dataRowCount < dt.Count; dataRowCount++)
{
//exclude the column 1 and 2 and any columns after 9
for (int columnNumber = 2; columnNumber < 8; columnNumber++)
{
Debug.Log(dr[dataRowCount][columnNumber].ToString());
msg += dr[dataRowCount][columnNumber].ToString();
}
}
C# NPOI draw line chart to Excel when cell value on range 0.001 to 9.999 (fractional numbers)
I can draw chart when cell value is similar (0, 1, 2, ... 9) or other integer value but when i try use (0,293 or other fractional numbers) i saw error:
"Removed part: /xl/drawings/drawing1.xml part. (Drawing figure)" (when open Excel file).
I tried searched solution in google and github but dont found simular situation.
Maybe some one faced with this issue.
Thanks for any help.
Updated added report files
Good report
Repot with error message
**Added code for explanation issues:**
class Program
{
const int NUM_OF_ROWS = 3;
const int NUM_OF_COLUMNS = 10;
static void CreateChart(IDrawing drawing, ISheet sheet, IClientAnchor anchor)
{
IChart chart = drawing.CreateChart(anchor);
IChartLegend legend = chart.GetOrCreateLegend();
legend.Position = LegendPosition.TopRight;
ILineChartData<double, double> data = chart.ChartDataFactory.CreateLineChartData<double, double>();
// Use a category axis for the bottom axis.
IChartAxis bottomAxis = chart.ChartAxisFactory.CreateCategoryAxis(AxisPosition.Bottom);
IValueAxis leftAxis = chart.ChartAxisFactory.CreateValueAxis(AxisPosition.Left);
IChartDataSource<double> xs = DataSources.FromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
IChartDataSource<double> ys1 = DataSources.FromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
data.AddSeries(xs, ys1);
chart.Plot(data, bottomAxis, leftAxis);
}
static void Main(string[] args)
{
IWorkbook wb = new XSSFWorkbook();
ISheet sheet = wb.CreateSheet("linechart");
// Create a row and put some cells in it. Rows are 0 based.
IRow row;
ICell cell;
for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++)
{
row = sheet.CreateRow((short)rowIndex);
for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++)
{
cell = row.CreateCell((short)colIndex);
//This generate graph
//cell.SetCellValue(colIndex * (rowIndex + 1));
//This make error when open Excel file
cell.SetCellValue(colIndex * (rowIndex + 1) + 0.1);
}
}
IDrawing drawing = sheet.CreateDrawingPatriarch();
IClientAnchor anchor1 = drawing.CreateAnchor(0, 0, 0, 0, 0, 5, 10, 8);
CreateChart(drawing, sheet, anchor1);
//Write to Excel file
using (FileStream fs =File.Create("test1.xlsx"))
{
wb.Write(fs);
}
}
}
I found solution - not perfect but it is works.
Set cell type to string.
Draw chart (with default value(0) becouse we use string cell type for draw)
Update cell type to numeric then chart will auto refresh with numeric data.
We have lots of old excel files that contain quite a bit of data. I am trying to get this data into SQL Server.
I have a C# application that I have used before to upload data from excel to SQL, the code is shown below.
The excel sheet has dates going across the sheet in row 4. The first date is in cell D4. There are id's (strings) going down from cell A5 to A11005. The values are of type double.
I am getting a System.OutOfMemoryException exception. I am surprised though as this error has been thrown on the 10,785th row & 333rd column. Is it really out of memory? I thought this wouldn't be a huge amount of data to be honest for a data table.
11,000 ids, 785 dates so 8,635,000 doubles. Is Visual Studio out of memory? I have a 64 bit PC with 32 GB RAM.
DataTable dt = new DataTable();
dt.Columns.Add("DateTM", typeof(DateTime));
dt.Columns.Add("Id", typeof(string));
dt.Columns.Add("Vtm", typeof(double));
OpenExcelWorkbook(path + fileName, true);
XlWorksheet = (Excel.Worksheet)XlWorkbook.Worksheets["Sheet1"];
Rng = XlWorksheet.UsedRange;
object[,] valueArray = (object[,])Rng.get_Value(Excel.XlRangeValueDataType.xlRangeValueDefault);
XlWorkbook.Close(false);
// dates start in cell D4
DateTime[] dates = new DateTime[valueArray.GetLength(1) - 3];
for (int t = 4; t <= valueArray.GetLength(1); t++)
dates[t - 4] = Convert.ToDateTime(valueArray[4, t]);
// values start from row 5
for (int n = 5; n <= valueArray.GetLength(0); n++)
{
string id = valueArray[n, 1].ToString().Trim();
// dates start from column D
for (int m = 4; m <= valueArray.GetLength(1); m++)
{
double vt = Convert.ToDouble(valueArray[n, m]);
if (vt == -2146826246) // for any #N/A values
vt = -999;
dt.Rows.Add(dates[m - 4], id, vt);
}
}
using (SqlBulkCopy sqlBulk = new SqlBulkCopy(UtilityLibrary.Database.Connections.Myconnection))
{
sqlBulk.BulkCopyTimeout = 0;
sqlBulk.DestinationTableName = "tblMyTbl";
sqlBulk.WriteToServer(dt);
}
List<someClass> aList = new List<someClass>();
...
XLWorkbook workbook = new XLWorkbook();
IXLWorksheet worksheet = workbook.AddWorksheet("Data");
worksheet.Hide();
workbook.CalculateMode = XLCalculateMode.Manual;
var data = aList.ToArray();
var firstCell = worksheet.Cell(1, 1);
var lastCell = worksheet.Cell(numRows, numColumns); // numRows = 150, numColumns = 8
var writeRange = worksheet.Range(firstCell, lastCell); //firstCell = A1, LastCell = H150
writeRange.Value = data;
workbook.SaveAs(mySavePath);
This bit of code is meant to copy the data in aList into a new excel document, only, instead of starting at cell A1(1,1) and ending at cell H150 it copies the value from cell 1 into all of the cells between A1 and H299, the row values that should be in row 1 into column H-O from row 1-150, and finally my correctly grouped data from H150-O299.
Basically, my data starts at the offset of the range instead of filling in the range, and everything above and left of that range is default copied (garbage) data. someClass is just a public class with public fields for ints and strings.
Can anyone tell me why this is happening and how I can correct it?
As a solution, I found that using the same index for first and last cell will properly input my data, however why Range does not work as (assumed) intended has yet to be answered.
var firstCell = worksheet.Cell(1, 1);
var writeRange = worksheet.Range(firstCell, firstCell); //firstCell = A1, LastCell = H150
This will work as intended. I've completely removed lastCell as it is unnecessary.
I have a table in Excel and I would like to import a selected area to a 2D array in excel. It must be same 2D array in C#. I have a picture, please look at it. I want to import that area to int array[81,81]:
You can use GemBox.Spreadsheet library for this (you can use its Free version to achieve this).
Here is a sample that you can use:
ExcelFile workbook = ExcelFile.Load("guncellenmis.xlsx");
ExcelWorksheet worksheet = workbook.Worksheets.ActiveWorksheet;
int count = 81;
int[,] data = new int[count, count];
// Get range from "C2" to "CE82".
CellRange range = worksheet.Cells.GetSubrangeRelative(1, 2, count, count);
// Or you can retrieve the required range differently, like:
//CellRange range = worksheet.Cells.GetSubrangeRelative("C2:CE82");
//CellRange range = worksheet.Cells.GetSubrangeRelative("C2", "CE82");
// etc.
for (int row = 0; row < range.Height; ++row)
for (int column = 0; column < range.Width; ++column)
data[row, column] = range[row, column].IntValue;
EDIT:
Is there a reason why you want to export the excel file as 2D array instead of DataTable.
You could retreive the required data as DataTable like the following:
ExcelFile workbook = ExcelFile.Load("guncellenmis.xlsx");
ExcelWorksheet worksheet = workbook.Worksheets.ActiveWorksheet;
DataTable table = worksheet.CreateDataTable(
new CreateDataTableOptions("C2", 81, 81));