Reading Excel using ClosedXML - Range is wrong - out-of-memory

I'm using ClosedXML to read in what appears to be a simple Excel file. But my program gets an out of memory exception.
Using some standard code to read in Excel sheet to a datatable:
public static void GetDataFromExcel(ref DataTable dt, string path, dynamic worksheet, bool header) //+EAG 6/8/2022
{
//Save the uploaded Excel file.
//DataTable dt = new DataTable();
//Open the Excel file using ClosedXML.
using (XLWorkbook workBook = new XLWorkbook(path))
{
//Read the first Sheet from Excel file.
IXLWorksheet workSheet = workBook.Worksheet(worksheet);
//Create a new DataTable.
// Does the first row contain headers ?
bool firstRow = false;
if (header) firstRow = true;
//Loop through the Worksheet rows.
foreach (IXLRow row in workSheet.Rows())
{
//Use the first row to add columns to DataTable.
if (firstRow)
{
foreach (IXLCell cell in row.Cells())
{
if (!string.IsNullOrEmpty(cell.Value.ToString()))
{
dt.Columns.Add(cell.Value.ToString());
}
else
{
break;
}
}
firstRow = false;
}
else
{
//Add rows to DataTable.
dt.Rows.Add();
int i = 0;
foreach (IXLCell cell in row.Cells())
{
string val = string.Empty;
try
{
val = cell.Value.ToString();
}
catch { }
dt.Rows[dt.Rows.Count - 1][i] = val;
i++;
}
}
}
}
}
The actual spreadsheet has only columns A -> O being used and there are only 130 rows in it. I've used this method in the same program to read in 3 other much larger spreadsheets without issue.
Not sure how to track down a solution to this. Any ideas ?

Related

ClosedXML how to freeze rows and columns when i export file

I have implemented the code below, all headers and data are added without any problem. If he wants to block the possibility of editing individual fields or columns in the excel file that is downloaded by the user, then there is a problem, because nothing is blocked
i use for freeze columns/rows, but when i export file and i open file i can edit any fields
worksheet.SheetView.Freeze(1,3);
[HttpGet]
public IActionResult ExportAsExcel()
{
IEnumerable<Employee> employees = this.repo.GetAll<Employee>();
List<EmployeeDTO> employeeDTO = this._mapper.Map<List<EmployeeDTO>>(employees);
using (var workbook = new XLWorkbook())
{
var woorksheet = workbook.Worksheets.Add("Sheet1");
var currentRow = 1;
woorksheet.Cell(currentRow, 1).Value = "ID";
woorksheet.Cell(currentRow, 2).Value = "name";
foreach (var empDtos in employeeDTO)
{
currentRow++;
woorksheet.Cell(currentRow, 1).Value = empDtos.EmployeeId;
woorksheet.Cell(currentRow, 2).Value = empDtos.Name;
}
using (var stream = new MemoryStream())
{
workbook.SaveAs(stream);
var content = stream.ToArray();
return File(
content,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Employee.xlsx"
);
}
}
}

CSV Helper first row been skipped

I am using CSV Helper to read a CSV file but the first row is been skipped, I saw that it can be a configuration but I can't see how to force the reading of the first row.
Any ideas?
try
{
using var csv = new CsvReader(file);
var records = csv.GetRecords<TMap>().ToList();
return _mapper.Map<List<T>>(records.ToList());
}
catch (Exception e)
{
throw new Exception($"Error parsing the Csv File. Error: {e.Message}");
}
you need to set the configuration first.
Try this
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
};
try
{
using var csv = new CsvReader(file, config);
var records = csv.GetRecords<TMap>().ToList();
return _mapper.Map<List<T>>(records.ToList());
}
catch (Exception e)
{
throw new Exception($"Error parsing the Csv File. Error: {e.Message}");
}

The most straightforward way to download a file in mvc

I am currently saving an excel file like so on my c drive.
public ActionResult Export()
{
try
{
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Add(System.Reflection.Missing.Value);
Excel.Worksheet worksheet = workbook.ActiveSheet;
var people = db.People.ToList();
worksheet.Cells[1, 1] = "Last Name";
worksheet.Cells[1, 2] = "First Name";
int row = 2;
foreach (var person in people)
{
worksheet.Cells[row, 1] = person.PersonFName;
worksheet.Cells[row, 2] = person.PersonLName;
row++;
}
workbook.SaveAs("c:\\test\\worksheet.xls");
workbook.Close();
Marshal.ReleaseComObject(workbook);
application.Quit();
Marshal.FinalReleaseComObject(application);
ViewBag.Result = "Done";
}
catch(Exception ex)
{
ViewBag.Result = ex.Message;
}
return File("c:\\test\\workseet.xls", "application/vnd.ms-excel", "workseet.xls");
// return View("Success");
}
I can go to c:\\test\workseet.xls and it exists there I can do what ever with it...
I am wanting to transform my method from return a view to return a file download...
I figured that it was as simple as this:
return File("c:\\test\\workseet.xls", "application/vnd.ms-excel", "workseet.xls");
However when I do this method and click the link to download, it gives me this error.
The process cannot access the file 'c:\test\workseet.xls' because it is being used by another process.
This duplicate question is just one of those that show how to use EPPlus to generate Excel files on the server side in a scaleable manner. It's actually a lot easier than using Excel interop and a lot faster. You don't even have to save the file to the disk.
public ActionResult ExportData()
{
//Somehow, load data to a DataTable
using (ExcelPackage package = new ExcelPackage())
{
var ws = package.Workbook.Worksheets.Add("My Sheet");
//true generates headers
ws.Cells["A1"].LoadFromDataTable(dataTable, true);
//Save the workbook to a stream
var stream = new MemoryStream();
package.SaveAs(stream);
string fileName = "myfilename.xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
stream.Position = 0;
return File(stream, contentType, fileName);
}
}
You can use LoadFromDataTable to fill a sheet from a data table or LoadFromCollection to load data from a collection, eg List<Sale>.
Both methods return an ExcelRange object (a range of cells) that you can use to format individual cells, rows, and columns. You can also create tables from a range and apply themes.
The duplicate goes even farther and shows how you can avoid even the MemoryStream

Codename One: Connecting and populating a drop-down menu with an SQLite database

I am trying to connect an SQLite database file to a picker component (accepting strings). This should act similar to a drop-down menu. I have tried to follow previous advice and examples, but without success.
As indicated in a previous post, I have saved the database file in the source folder of the application. View of the source folder where I have saved the database file (highlighted).
The code I have used to implement my app is as follows with the below layout.
//-----------------------
database code
//-----------------------
public class MyApplication {
private Form current;
private Resources theme;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Pro only feature, uncomment if you have a pro subscription
// Log.bindCrashProtection(true);
}
private Container Home() {
Container home = new Container(new BoxLayout(BoxLayout.Y_AXIS));
return home;
}
private Container AddItem() {
Container addItem = new Container(new BoxLayout(BoxLayout.Y_AXIS));
TextArea item = new TextArea("Add Item");
addItem.addComponent(item);
Picker selectItem = new Picker();
selectItem.setType(Display.PICKER_TYPE_STRINGS);
//----------------------------------------------------------------------------------
Database db = null;
Cursor cur = null;
try {
db = Display.getInstance().openOrCreate("FoodAndBeverage.db");
if(selectItem.getText().startsWith("Still Water")) {
cur = db.executeQuery(selectItem.getText());
int columns = cur.getColumnCount();
addItem.removeAll();
if(columns > 0) {
boolean next = cur.next();
if(next) {
ArrayList<String[]> data = new ArrayList<>();
String[] columnNames = new String[columns];
for(int iter = 0 ; iter < columns ; iter++) {
columnNames[iter] = cur.getColumnName(iter);
}
while(next) {
Row currentRow = cur.getRow();
String[] currentRowArray = new String[columns];
for(int iter = 0 ; iter < columns ; iter++) {
currentRowArray[iter] = currentRow.getString(iter);
}
data.add(currentRowArray);
next = cur.next();
}
Object[][] arr = new Object[data.size()][];
data.toArray(arr);
addItem.add(BorderLayout.CENTER, new Table(new DefaultTableModel(columnNames, arr)));
} else {
addItem.add(BorderLayout.CENTER, "Query returned no results");
}
} else {
addItem.add(BorderLayout.CENTER, "Query returned no results");
}
} else {
db.execute(selectItem.getText());
addItem.add(BorderLayout.CENTER, "Query completed successfully");
}
addItem.revalidate();
} catch(IOException err) {
Log.e(err);
addItem.removeAll();
addItem.add(BorderLayout.CENTER, "Error: " + err);
addItem.revalidate();
} finally {
Util.cleanup(db);
Util.cleanup(cur);
}
//---------------------------------------------------------------------------------------------
addItem.addComponent(selectItem);
TextField quantity = new TextField("", "Quantity (ml or g)", 4, TextArea.NUMERIC);
addItem.addComponent(quantity);
Button add = new Button("Add");
addItem.addComponent(add);
TextArea results = new TextArea("Results");
addItem.addComponent(results);
return addItem;
}
private Container Settings() {
Container settings = new Container(new BoxLayout(BoxLayout.Y_AXIS));
TextArea nutrients = new TextArea("Target");
settings.addComponent(nutrients);
TextField volume = new TextField("", "Volume (ml)", 4, TextArea.NUMERIC);
settings.addComponent(volume);
TextArea duration = new TextArea("Hydration Duration");
settings.addComponent(duration);
settings.add("Start:");
Picker start = new Picker();
start.setType(Display.PICKER_TYPE_TIME);
settings.addComponent(start);
settings.add("End:");
Picker end = new Picker();
end.setType(Display.PICKER_TYPE_TIME);
settings.addComponent(end);
Button save = new Button("Save");
settings.addComponent(save);
return settings;
}
public void start() {
if(current != null)
{
current.show();
return;
}
Form home = new Form("Hydrate", new BorderLayout());
Tabs t = new Tabs();
t.addTab("Home", Home());
t.addTab("Intake", AddItem());
t.addTab("Settings", Settings());
home.add(BorderLayout.NORTH, t);
home.show();
}
public void stop() {
current = Display.getInstance().getCurrent();
}
public void destroy() {
}
}
I would therefore appreciate any advice and guidance on exactly where I am going wrong and how to implement the suggested changes in my code.
I'm assuming the file under src does indeed end with the extension db as the Windows hidden extensions nonsense is turned on.
This code will NOT open a db placed in src:
db = Display.getInstance().openOrCreate("FoodAndBeverage.db");
You need to do something like this to implicitly initialize the DB the first time the app is installed:
String path = Display.getInstance().getDatabasePath("FoodAndBeverage.db");
FileSystemStorage fs = FileSystemStorage.getInstance();
if(!fs.exists(path)) {
try (InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/FoodAndBeverage.db");
OutputStream os = fs.openOutputStream(path)) {
Util.copy(is, os);
} catch(IOException err) {
Log.e(err);
}
}
db = Display.getInstance().openOrCreate("FoodAndBeverage.db");
Notice that the code above doesn't check for updates of the DB so assuming the DB is read only you might want to update/merge it with app updates.
The above code doesn't work on Android device, this works only on simulator. I have tested multiple times in the android device. In the real android device ,the database is not loaded at all, shows sql exception error
"No such table sql exception".
Looks like preloaded sqlite .db file is never tested on real Android device.

How to put xml code for a subreport in xtrareport devexpress?

I created a master report file. Then I created subreport file. Is there a way to put xml code of the subreport file as a report source ?
Override OnBeforePrint method and go through XtraReportBase.Controls property tree to find XRSubreport. As described here you can use DataSet and its DataSet.ReadXml method:
protected override void OnBeforePrint(PrintEventArgs e)
{
base.OnBeforePrint(e);
//Get your xml here
var dataSet = new DataSet();
using (var reader = new StringReader(xml))
dataSet.ReadXml(reader);
SetSubReportXML(this, dataSet);
}
private void SetSubReportXML(XRControl xrControl, DataSet dataSet)
{
foreach (XRControl xrControlChild in xrControl.Controls)
{
var subReport = xrControlChild as XRSubreport;
if (subReport != null)
{
//Set your xml here
subReport.ReportSource.DataSource = dataSet;
subReport.ReportSource.DataMember = this.DataMember;
SetSubReportXML(subReport.ReportSource, dataSet);
}
SetSubReportXML(xrControlChild, dataSet);
}
}

Resources