Reading XLSM file with c# wihtout excel installed - c#

Hello so I was given a Project were I needed to read a xlsm file and then Project the result into a DataGripView, this is what I have so far.
var filename = "Filename|.xlsm"
XLWorkbook workbook = null;
try
{
workbook = new XLWorkbook(filename);
}
catch (Exception)
{
labelResult.Text = "error message";
return;
}
IXLWorksheet ws = null;
bool success = workbook.Worksheets.TryGetWorksheet("Cell", out ws);
if(!success)
{
labelResult.Text = "error message.";
return;
}
List<MyList> listnum = new List<MyList>();
foreach (var row in ws.RowsUsed())
{
MyList ML = new MyList { };
ML.statecod = row.Cell(1).GetString();
ML.state = row.Cell(2).GetString();
dataGridView1.DataSource = listnum;
}
So how do I populate my datagridview with the data from a xlsm file without having excel installed, therefore no excel libraries and no use of oledb?

So I found the answer. Just needed to add: listnum.add(ML);
I forgot to add my list, silly me...

Related

C# Exporting from database to excel returns a hexadecimal error

I am reading a List from my database and I only need to export 1 column of this data into an excel sheet. However, the try catch method is catching the following Hex error "0x800AC472".
try
{
var path = #"C:\Users\Desktop\Data.xlsx";
var listOfUsers = _context.Users.ToList();
int row = 2;
Microsoft.Office.Interop.Excel.Application excel;
Microsoft.Office.Interop.Excel.Workbook excelworkBook;
Microsoft.Office.Interop.Excel.Worksheet excelSheet;
Microsoft.Office.Interop.Excel.Range excelCellrange;
excel = new Microsoft.Office.Interop.Excel.Application();
excel.Visible = false;
excel.Interactive = false;
excel.DisplayAlerts = false;
excelworkBook = excel.Workbooks.Add(Type.Missing);
excelSheet = (Microsoft.Office.Interop.Excel.Worksheet)excelworkBook.ActiveSheet;
excelSheet.Name = "Test work sheet";
excelCellrange = excelSheet.Range[excelSheet.Cells[1, 1], excelSheet.Cells[listOfUsers.Count, 1]];
excelCellrange.EntireColumn.AutoFit();
excelSheet.Cells[1, 1] = "Phone Number";
foreach (var user in listOfUsers)
{
excelSheet.Cells[row, 1] = user.PhoneNumber;
row++;
}
excelSheet.SaveAs(path);
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.Message); ;
}
Update:
Turns out the issue was in MS Office license. It was expired. Once I fixed the license everything worked out.
Based on this topic: https://social.msdn.microsoft.com/Forums/en-US/9168f9f2-e5bc-4535-8d7d-4e374ab8ff09/hresult-800ac472-from-set-operations-in-excel?forum=vsto it seems that this error is a result of excel wanting to prompt the user for some sort of input but being unable to.
Consider instead using a library like EPPlus instead. Watch out of the licensing though, it changed from LGPL to Polyform from version 5. https://www.nuget.org/packages/EPPlus/4.5.3.3

How to convert excel in API side?

As question, How to convert excel in API and transfer as file back to the service?
Currently I able to get the data from database already but after getting the data from it, I'm not sure how to convert the data to excel before send back to the service. I need to convert it in api instead of in angular component side after getting the full completed of data from API.
[Route("getExcelData")]
[Authenticate]
[HttpPost]
public IHttpActionResult GetExcelData([FromBody]Report obj)
{
try
{
this.Contents.Add("Result", new ReportService().getExcelData(obj.Id, obj.FromDate, obj.ToDate));
return JsonResponse();
}
catch (Exception e)
{
LogManager.Instance.InsertLog(LogLevel.Error, e.Message, e.StackTrace, "ReportController", "ReportController", null, null);
ExceptionManager.Instance.Add(String.Format("GetData Failed: {0}", e.Message), $"{e.StackTrace} Inner Exception: {e.InnerException}");
this.Contents.Add("Result", null);
return JsonResponse();
}
}
Below code worked for me.
please find more elobarations here.
#region Loading the data to DataGridView
DataSet customersDataSet = new DataSet();
//Read the XML file with data
string inputXmlPath = Path.GetFullPath(#"../../Data/Employees.xml");
customersDataSet.ReadXml(inputXmlPath);
DataTable dataTable = new DataTable();
//Copy the structure and data of the table
dataTable = customersDataSet.Tables[1].Copy();
//Removing unwanted columns
dataTable.Columns.RemoveAt(0);
dataTable.Columns.RemoveAt(10);
this.dataGridView1.DataSource = dataTable;
dataGridView1.AlternatingRowsDefaultCellStyle.BackColor = Color.White;
dataGridView1.RowsDefaultCellStyle.BackColor = Color.LightBlue;
dataGridView1.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("Tahoma", 9F, ((System.Drawing.FontStyle)(System.Drawing.FontStyle.Bold)));
dataGridView1.ForeColor = Color.Black;
dataGridView1.BorderStyle = BorderStyle.None;
#endregion
using (ExcelEngine excelEngine = new ExcelEngine())
{
IApplication application = excelEngine.Excel;
//Create a workbook with single worksheet
IWorkbook workbook = application.Workbooks.Create(1);
IWorksheet worksheet = workbook.Worksheets[0];
//Import from DataGridView to worksheet
worksheet.ImportDataGridView(dataGridView1, 1, 1, isImportHeader: true, isImportStyle: true);
worksheet.UsedRange.AutofitColumns();
workbook.SaveAs("Output.xlsx");
}

How to create(export) excel file readonly using Open Xml 2.5 SDK

I am developing one WPF application (using MVVM). I am also able to export my List to Excel file.But my problem is I am not able to make it readonly, so no one can able to make changes afterwards.
document.WorkbookPart.Workbook.WorkbookProtection=new WorkbookProtection
{
LockStructure=true
};
I only found this, but it's only make workbook readonly
Here is my code for creating excel file
public static bool CreateExcelDocument(DataSet ds, string excelFilename)
{
try
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(excelFilename, SpreadsheetDocumentType.Workbook))
{
document.AddWorkbookPart();
document.WorkbookPart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();
document.WorkbookPart.Workbook.WorkbookProtection=new WorkbookProtection
{
LockStructure = true,
};
// My thanks to James Miera for the following line of code (which prevents crashes in Excel 2010)
document.WorkbookPart.Workbook.Append(new BookViews(new WorkbookView()));
// If we don't add a "WorkbookStylesPart", OLEDB will refuse to connect to this .xlsx file !
WorkbookStylesPart workbookStylesPart = document.WorkbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles");
Stylesheet stylesheet = new Stylesheet();
workbookStylesPart.Stylesheet = stylesheet;
CreateParts(ds, document);
}
Trace.WriteLine("Successfully created: " + excelFilename);
return true;
}
catch (Exception ex)
{
Trace.WriteLine("Failed, exception thrown: " + ex.Message);
return false;
}
}
private static void CreateParts(DataSet ds, SpreadsheetDocument spreadsheet)
{
// Loop through each of the DataTables in our DataSet, and create a new Excel Worksheet for each.
uint worksheetNumber = 1;
foreach (DataTable dt in ds.Tables)
{
// For each worksheet you want to create
string workSheetID = "rId" + worksheetNumber.ToString();
string worksheetName = dt.TableName;
WorksheetPart newWorksheetPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>();
newWorksheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet();
// create sheet data
newWorksheetPart.Worksheet.AppendChild(new DocumentFormat.OpenXml.Spreadsheet.SheetData());
// save worksheet
WriteDataTableToExcelWorksheet(dt, newWorksheetPart);
newWorksheetPart.Worksheet.Save();
// create the worksheet to workbook relation
if (worksheetNumber == 1)
spreadsheet.WorkbookPart.Workbook.AppendChild(new DocumentFormat.OpenXml.Spreadsheet.Sheets());
spreadsheet.WorkbookPart.Workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>().AppendChild(new DocumentFormat.OpenXml.Spreadsheet.Sheet()
{
Id = spreadsheet.WorkbookPart.GetIdOfPart(newWorksheetPart),
SheetId = (uint)worksheetNumber,
Name = dt.TableName
});
worksheetNumber++;
}
spreadsheet.WorkbookPart.Workbook.Save();
}
Before you open Excel, you can Lock your file with:
FileInfo cInfo = new FileInfo(Path);
cInfo.IsReadonly = true;
Than it will be readonly.

Is there any simple way to convert .xls file to .csv file? (Excel)

Is there any simple way to convert .xls file to .csv file ? (Excel)
in C# code ?
I mean to take an existing .xls file and convert them to .csv file
Here's a C# method to do this. Remember to add your own error handling - this mostly assumes that things work for the sake of brevity. It's 4.0+ framework only, but that's mostly because of the optional worksheetNumber parameter. You can overload the method if you need to support earlier versions.
static void ConvertExcelToCsv(string excelFilePath, string csvOutputFile, int worksheetNumber = 1) {
if (!File.Exists(excelFilePath)) throw new FileNotFoundException(excelFilePath);
if (File.Exists(csvOutputFile)) throw new ArgumentException("File exists: " + csvOutputFile);
// connection string
var cnnStr = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;IMEX=1;HDR=NO\"", excelFilePath);
var cnn = new OleDbConnection(cnnStr);
// get schema, then data
var dt = new DataTable();
try {
cnn.Open();
var schemaTable = cnn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (schemaTable.Rows.Count < worksheetNumber) throw new ArgumentException("The worksheet number provided cannot be found in the spreadsheet");
string worksheet = schemaTable.Rows[worksheetNumber - 1]["table_name"].ToString().Replace("'", "");
string sql = String.Format("select * from [{0}]", worksheet);
var da = new OleDbDataAdapter(sql, cnn);
da.Fill(dt);
}
catch (Exception e) {
// ???
throw e;
}
finally {
// free resources
cnn.Close();
}
// write out CSV data
using (var wtr = new StreamWriter(csvOutputFile)) {
foreach (DataRow row in dt.Rows) {
bool firstLine = true;
foreach (DataColumn col in dt.Columns) {
if (!firstLine) { wtr.Write(","); } else { firstLine = false; }
var data = row[col.ColumnName].ToString().Replace("\"", "\"\"");
wtr.Write(String.Format("\"{0}\"", data));
}
wtr.WriteLine();
}
}
}
Checkout the .SaveAs() method in Excel object.
wbWorkbook.SaveAs("c:\yourdesiredFilename.csv", Microsoft.Office.Interop.Excel.XlFileFormat.xlCSV)
Or following:
public static void SaveAs()
{
Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.ApplicationClass();
Microsoft.Office.Interop.Excel.Workbook wbWorkbook = app.Workbooks.Add(Type.Missing);
Microsoft.Office.Interop.Excel.Sheets wsSheet = wbWorkbook.Worksheets;
Microsoft.Office.Interop.Excel.Worksheet CurSheet = (Microsoft.Office.Interop.Excel.Worksheet)wsSheet[1];
Microsoft.Office.Interop.Excel.Range thisCell = (Microsoft.Office.Interop.Excel.Range)CurSheet.Cells[1, 1];
thisCell.Value2 = "This is a test.";
wbWorkbook.SaveAs(#"c:\one.xls", Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlShared, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
wbWorkbook.SaveAs(#"c:\two.csv", Microsoft.Office.Interop.Excel.XlFileFormat.xlCSVWindows, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlShared, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
wbWorkbook.Close(false, "", true);
}
Install these 2 packages
<packages>
<package id="ExcelDataReader" version="3.3.0" targetFramework="net451" />
<package id="ExcelDataReader.DataSet" version="3.3.0" targetFramework="net451" />
</packages>
Helper function
using ExcelDataReader;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExcelToCsv
{
public class ExcelFileHelper
{
public static bool SaveAsCsv(string excelFilePath, string destinationCsvFilePath)
{
using (var stream = new FileStream(excelFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
IExcelDataReader reader = null;
if (excelFilePath.EndsWith(".xls"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else if (excelFilePath.EndsWith(".xlsx"))
{
reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
}
if (reader == null)
return false;
var ds = reader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
{
UseHeaderRow = false
}
});
var csvContent = string.Empty;
int row_no = 0;
while (row_no < ds.Tables[0].Rows.Count)
{
var arr = new List<string>();
for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
{
arr.Add(ds.Tables[0].Rows[row_no][i].ToString());
}
row_no++;
csvContent += string.Join(",", arr) + "\n";
}
StreamWriter csv = new StreamWriter(destinationCsvFilePath, false);
csv.Write(csvContent);
csv.Close();
return true;
}
}
}
}
Usage :
var excelFilePath = Console.ReadLine();
string output = Path.ChangeExtension(excelFilePath, ".csv");
ExcelFileHelper.SaveAsCsv(excelFilePath, output);
I had to come up with a hybrid solution after updating to Visual Studio 2022 and testing the most relevant answers for this to work.
First, we need to install the following Nuget packages: ExcelDataReader, ExcelDataReader.DataSet and System.Text.Encoding.CodePages
Then, for the sake of clean architecture, proceed to create a separate class within your corresponding namespace:
using ExcelDataReader;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace YourProjectNameSpace
{
public class ExcelFileHelper
{
/// <summary>
/// Converts a given XLS into CSV file format.
/// </summary>
public static bool SaveAsCsv(string excelFilePath, string destinationCsvFilePath)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
using (var stream = new FileStream(excelFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
IExcelDataReader reader = null;
if (excelFilePath.EndsWith(".xls"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else if (excelFilePath.EndsWith(".xlsx"))
{
reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
}
if (reader == null)
return false;
var ds = reader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
{
UseHeaderRow = false
}
});
var csvContent = string.Empty;
int row_no = 0;
while (row_no < ds.Tables[0].Rows.Count)
{
var arr = new List<string>();
for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
{
arr.Add(ds.Tables[0].Rows[row_no][i].ToString());
}
row_no++;
csvContent += string.Join(",", arr) + "\n";
}
StreamWriter csv = new StreamWriter(destinationCsvFilePath, false);
csv.Write(csvContent);
csv.Close();
return true;
}
}
}
}
Notice I had to include this line at the beginning of the function:
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
If the line from above is omitted, you could end up getting the following error:
NotSupportedException: No data is available for encoding 1252
So, make sure of using it for better compatibility.
Finally, use example:
var execPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)?.Replace("file:\\", "");
string FileNameXLS = "\\file.xls";
string FileNameCSV = "\\file.csv";
Console.WriteLine("Exporting file to CSV...." + "\n");
ExcelFileHelper.SaveAsCsv(execPath + FileNameXLS, execPath + FileNameCSV);
Console.WriteLine("File exported to CSV!" + "\n");
I need to do the same thing. I ended up with something similar to Kman
static void ExcelToCSVCoversion(string sourceFile, string targetFile)
{
Application rawData = new Application();
try
{
Workbook workbook = rawData.Workbooks.Open(sourceFile);
Worksheet ws = (Worksheet) workbook.Sheets[1];
ws.SaveAs(targetFile, XlFileFormat.xlCSV);
Marshal.ReleaseComObject(ws);
}
finally
{
rawData.DisplayAlerts = false;
rawData.Quit();
Marshal.ReleaseComObject(rawData);
}
Console.WriteLine();
Console.WriteLine($"The excel file {sourceFile} has been converted into {targetFile} (CSV format).");
Console.WriteLine();
}
If there are multiple sheets this is lost in the conversion but you could loop over the number of sheets and save each one as csv.
This is a modification of nate_weldon's answer with a few improvements:
More robust releasing of Excel objects
Set application.DisplayAlerts = false; before attempting to save to hide prompts
Also note that the application.Workbooks.Open and ws.SaveAs methods expect sourceFilePath and targetFilePath to be full paths (ie. directory path + filename)
private static void SaveAs(string sourceFilePath, string targetFilePath)
{
Application application = null;
Workbook wb = null;
Worksheet ws = null;
try
{
application = new Application();
application.DisplayAlerts = false;
wb = application.Workbooks.Open(sourceFilePath);
ws = (Worksheet)wb.Sheets[1];
ws.SaveAs(targetFilePath, XlFileFormat.xlCSV);
}
catch (Exception e)
{
// Handle exception
}
finally
{
if (application != null) application.Quit();
if (ws != null) Marshal.ReleaseComObject(ws);
if (wb != null) Marshal.ReleaseComObject(wb);
if (application != null) Marshal.ReleaseComObject(application);
}
}
I integrate the #mattmc3 aswer. If you want to convert a xlsx file you should use this connection string (the string provided by matt works for xls formats, not xlsx):
var cnnStr = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;IMEX=1;HDR=NO\"", excelFilePath);
I had a similar task issue. Convert an inbound transactions like xlsx to tab delimited for automated processing by an existing system. Needs to run unattended. After reviewing many solutions on several different sites, and trying two of them, using MS Office Excel for C#, like above, and running into issues with different versions of MS Office, and older versions possibly on the PC, and having no control over that. I ended up going with... Aspose.Cells through NuGet. Solution is four lines of code.
string soureFilePath = "my/source/path/file.xlsx";
string targetFilePath = "my/output/path/file.txt";
var book = new Workbook(soureFilePath);
book.Save(targetFilePath, SaveFormat.Tsv);
It only converts sheet 1, and ignored sheets 2 and 3, but that is Ok for my use. I'm guessing it does have functionality to convert all of them if needed, I just did not need that, so did not look into it.
Their web site, incase folks want to view their information or license agreement (no cost use).
Manipulate Spreadsheets Easily | Aspose.Cells Universal Library
https://products.aspose.com/cells
Note: I do not work for Aspose, I am not affiliated with Aspose, and I am not profiting in any way from this posting.
I maintain some libraries that make the Excel to CSV conversion about as simple as it can be: Sylvan.Data.Excel and Sylvan.Data.Csv. Sylvan.Data.Excel can be used to read .xlsx, .xlsb, and .xls files. However, it can only write .xlsx files.
Here is a minimal example of converting an Excel spreadsheet to CSV:
using Sylvan.Data.Csv;
using Sylvan.Data.Excel;
using var reader = ExcelDataReader.Create("MyData.xlsx");
using var csvWriter = CsvDataWriter.Create("MyData.csv");
csvWriter.Write(reader);
These libraries have no external dependencies, other than the .NET runtime libraries; they don't require Excel be installed. They target the latest supported .NET versions and can run cross-platform. They are also the fastest libraries in the .NET ecosystem. They are MIT licensed, so can be freely used.

how to create excel sheet from template excel sheet programmatically?

I am creating a excel sheet from tempalte excel sheet.
I have a code
try
{
FileInfo newFile = new FileInfo(#"D:\ExcelFromTemplate.xlsx");
FileInfo template = new FileInfo(#"D:\template.xlsx");
using (ExcelPackage xlPackage = new ExcelPackage(newFile, template))
{
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets["Sheet1"];
ExcelCell cell = worksheet.Cell(5,1);
cell.Value = "15";
//worksheet.Cell(5, 1).Value = "Soap";
//xlPackage.Save();
Response.Write("Excel file created successfully");
}
}
catch (Exception ex)
{
Response.WriteFile(ex.InnerException.ToString());
}
this code creates the new excel file same as the template excel file but could not add the cell value. Why?
I had tried it with 2 ways as in above code for cell(5,1). But the excel sheet creates without writting cell value. How we can add it.
You need to save the file to persist the changes made. Using save()
try
{
FileInfo newFile = new FileInfo(#"D:\ExcelFromTemplate.xlsx");
FileInfo template = new FileInfo(#"C:\Example.xlsx");
using (ExcelPackage xlPackage = new ExcelPackage(newFile , template))
{
//Added This part
foreach (ExcelWorksheet aworksheet in xlPackage.Workbook.Worksheets)
{
aworksheet.Cell(1, 1).Value = aworksheet.Cell(1, 1).Value;
}
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets["My Data"];
ExcelCell cell = worksheet.Cell(5, 1);
cell.Value = "15";
//worksheet.Cell(5, 1).Value = "Soap";
xlPackage.Save( );
//Response.Write("Excel file created successfully");
}
}
catch (Exception ex)
{
//Response.WriteFile(ex.InnerException.ToString());
}
Got the issue. The problem is inherent to ExcelPackage.
For the same you have to open each sheet and do some changes for it to get saved.
Search the forum for more explanation.

Categories

Resources