I tried to use Spire.Xls library, but it does not support .xlsm and when i convert it to .xlsx hasn`t saved it, same with Microsoft.Office.Excel.Interop.
private void button1_Click(object sender, EventArgs e)
{
//string xlsm = #"D:\foot_Regular B07BNJ56GV B07BNK8S3Q B07BMX2NN4 with3.xlsm";
string xlsx = #"D:\foot_Regular B07BNJ56GV B07BNK8S3Q B07BMX2NN4 with3.xlsx";
//ConverXlsmToXlsx(xlsm, xlsx);
//string xlsx = #"D:\1.xlsx";
/* Load Excel File */
Excel.Application excelApp = new Excel.Application();
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(xlsx, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
/* Load worksheets collection */
Excel.Sheets excelSheets = excelWorkbook.Worksheets;
/* Select first worksheet */
Excel.Worksheet excelWorksheet = (Excel.Worksheet)excelSheets[1];
/* Deleting first 87 Rows */
Excel.Range range = excelWorksheet.get_Range("1:87").EntireRow;
range.Delete(Excel.XlDeleteShiftDirection.xlShiftUp);
/* Save File */
excelWorkbook.SaveAs(#"D:\out_file.xlsx");
excelWorkbook.Close(false);
excelApp.Application.Quit();
/* Release COM objects otherwise Excel remain running */
releaseObject(range);
releaseObject(excelWorkbook);
releaseObject(excelWorksheet);
releaseObject(excelApp);
MessageBox.Show("Finished");
}
Conver function:
public static void ConverXlsmToXlsx(string path, string outputPath)
{
byte[] byteArray = File.ReadAllBytes(path);
using (MemoryStream stream = new MemoryStream())
{
stream.Write(byteArray, 0, (int)byteArray.Length);
using (SpreadsheetDocument spreadsheetDoc = SpreadsheetDocument.Open(stream, true))
{
// Change from template type to workbook type
spreadsheetDoc.ChangeDocumentType(SpreadsheetDocumentType.Workbook);
}
File.WriteAllBytes(outputPath, stream.ToArray());
}
}
How i can easy work with .xlsm files via C#?
Help please with it, I would really appreciate it.
EPPlus seems to be the library to use.
You don't need Interop or an actual installation of MS Excel.
They have a sample how to work with VBA macros, but it seems your problem was just reading and saving files without touching the macros, so you should be good with their basic samples:
using (ExcelPackage package = new ExcelPackage(newFile))
{
// make your modifications
package.Save();
}
I personally use ClosedXML.
ClosedXML makes it easier for developers to create Excel 2007+ (.xlsx, .xlsm, etc) files. It provides a nice object oriented way to manipulate the files (similar to VBA) without dealing with the hassles of XML Documents. It can be used by any .NET language like C# and VisualBasic.NET.
You can find more details here.
Spire.XLS supports .xlsm files, here is the code to directly delete rows from a xlsm file with it:
Workbook workbook = new Workbook();
workbook.LoadFromFile("Input.xlsm");
Worksheet sheet = workbook.Worksheets[0];
sheet.DeleteRow(1,87);
workbook.SaveToFile("Output.xlsm", ExcelVersion.Version2007);
I use the Spire.XLS Pack(Hotfix) Version:8.6.6
Related
I have come across two spreadsheets giving me errors when using Open XML SDK to convert.
The cases are:
Read-only password protection (I don't have password)
Filesharing enabled (another user on the network has the spreadsheet open and spreadsheet is read-only until user closes spreadsheet)
If I use Excel Interop, it is possible to give parameters that will open a copy of the spreadsheet and enable write permissions and hence any programmatic conversion process can continue. This code enables the behaviour by utilising IgnoreReadOnlyRecommended
// Convert legacy Excel files to .xlsx Transitional using Microsoft Office Interop Excel
public bool Convert_Legacy_ExcelInterop(string input_filepath, string output_filepath)
{
bool convert_success = false;
// Open Excel
Excel.Application app = new Excel.Application(); // Create Excel object instance
app.DisplayAlerts = false; // Don't display any Excel prompts
Excel.Workbook wb = app.Workbooks.Open(input_filepath, ReadOnly: false, Password: "'", WriteResPassword: "'", IgnoreReadOnlyRecommended: true, Notify: false); // Create workbook instance
// Save workbook as .xlsx Transitional and close Excel
wb.SaveAs(output_filepath, 51);
wb.Close();
app.Quit();
return convert_success = true;
}
How can I imitate the same behaviour using Open XML SDK?
Here's my code:
// Convert to .xlsx Transitional
public bool Convert_to_OOXML_Transitional(string input_filepath, string output_filepath)
{
bool convert_success = false;
// If write-protected or reserved by another user
using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(input_filepath, false))
{
if (spreadsheet.WorkbookPart.Workbook.WorkbookProtection != null || spreadsheet.WorkbookPart.Workbook.FileSharing != null)
{
// Use Excel Interop to convert the spreadsheet
Convert_Legacy_ExcelInterop(input_filepath, output_filepath);
return convert_success = true;
// REPLACE ABOVE CODE WITH SOMETHING NATIVE TO OPEN XML SDK
}
}
// Convert spreadsheet
byte[] byteArray = File.ReadAllBytes(input_filepath);
using (MemoryStream stream = new MemoryStream())
{
stream.Write(byteArray, 0, (int)byteArray.Length);
using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(stream, true))
{
spreadsheet.ChangeDocumentType(SpreadsheetDocumentType.Workbook);
}
File.WriteAllBytes(output_filepath, stream.ToArray());
}
// Repair spreadsheet
Repair rep = new Repair();
rep.Repair_OOXML(output_filepath);
// Return success
convert_success = true;
return convert_success;
}
I have an ASP.NET Web API and need to implement this feature for a future version. Specifically:
Several .xls files will be placed in a temporary folder. They have the same width but different heights, as well as different row and column sizes.
The files need to be appended into one .xls file
The final excel cannot have multiple worksheets.
The Office Interop libraries cannot be used because Office is not installed and cannot be instaled on the deployment environment.
Is there a way to do this without using the office interop libraries as specified, or any paid third party libraries (free third party libraries are more than welcome) ?
Install Spire.XLS from NuGet: Install-Package Spire.XLS -Version 9.6.7
Spire.XLS provides two ways to merge excel files into a single excel worksheet:
1. Merge excel with styles using CellRange.Copy()
static void Main(string[] args)
{
string outputPath = "‪output.xls";
List<string> files = new List<string>();
files.Add(#"File1.xls");
files.Add(#"File2.xls");
CombineFiles(files, outputPath);
}
private static void CombineFiles(List<string> files, string outputPath)
{
Spire.Xls.Workbook resultworkbook = new Spire.Xls.Workbook();
resultworkbook.Worksheets.Clear();
Spire.Xls.Worksheet resultworksheet = resultworkbook.Worksheets.Add("worksheet");
Spire.Xls.Workbook workbook = new Spire.Xls.Workbook();
for (int i = 0; i < files.Count; i++)
{
workbook.LoadFromFile(files[i]);
Worksheet sheet = workbook.Worksheets[0];
if (i == 0)
{
sheet.AllocatedRange.Copy(resultworksheet.Range[1, 1], true, true);
}
else
{
sheet.AllocatedRange.Copy(resultworksheet.Range[resultworksheet.LastRow + 1, 1], true, true);
}
}
resultworkbook.SaveToFile(outputPath, ExcelVersion.Version97to2003);
}
Reference: How to merge multiple worksheets to a single worksheet with styles
2. Merge excel without styles using DataTable
Workbook workbook1 = new Workbook();
//load the first workbook
workbook1.LoadFromFile(FilePath1);
//load the second workbook
Workbook workbook2 = new Workbook();
workbook2.LoadFromFile(FilePath2);
//load the third workbook
Workbook workbook3 = new Workbook();
workbook3.LoadFromFile(FilePath3);
//import the second and third workbook's first worksheet into the first workbook using datatable
Worksheet sheet1 = workbook1.Worksheets[0];
Worksheet sheet2 = workbook2.Worksheets[0];
Worksheet sheet3 = workbook3.Worksheets[0];
DataTable dataTable1 = sheet2.ExportDataTable();
DataTable dataTable2 = sheet3.ExportDataTable();
sheet1.InsertDataTable(dataTable1, false, sheet1.LastRow + 1, 1);
sheet1.InsertDataTable(dataTable2, false, sheet1.LastRow + 1, 1);
workbook1.SaveToFile(OutputPath + "Merged.xls", ExcelVersion.Version97to2003);
Reference: How to merge 3 Sheets from different Excel files into one sheet with C#
I receive some reports in an xslx file that has 2 sheets, the data is good but there's no formatting done on the file. Most of the posts I found talk about formatting the file while creating it, but I'm wondering if there's a way I can work the file with c# code after receiving it (ex : fit columns to content)?
Thank you.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClosedXML;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.CSharp;
using DocumentFormat.OpenXml.Office.Excel;
namespace ExcelFormatter
{
class MainScript
{
public static void Main(string[] args)
{
string file = args[0];
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
Excel.Range chartRange;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Add(file);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
chartRange = xlWorkSheet.get_Range("A1", "F1");
chartRange.Cells.Font.Bold = true;
xlWorkBook.Save();
xlWorkBook.Close(true, file, misValue);
xlApp.Quit();
}
}
}
I use ClosedXML to manipulate Excel files that have been created using the OpenXML standard. It found it to be easy to use and allowed me to do a lot of things to my documents. Hope this helps.
Wade
Here is an example of what I have done. It is in VB.Net, but you should be able to convert it with no problem.
'Open the workbook and then open the worksheet I want to work with.
Dim workbook = New XLWorkbook("<filepath>")
Dim worksheet = workbook.Worksheet("<worksheetname>")
' Throw an exception if there is no sheet.
If worksheet Is Nothing Then
Throw New ArgumentException("Sheet is missing")
End If
'Set number formatting. You can look at the closedxml documentation to see what the number should be
worksheet.Cell("G5").Style.NumberFormat.SetNumberFormatId(1)
'Merge and style a group of cells
Dim cellRange = "A1:A12"
worksheet.Range(cellRange).Merge.Value = colName
worksheet.Range(cellRange).Style.Fill.BackgroundColor = XLColor.Black
worksheet.Range(cellRange).Style.Font.FontColor = XLColor.White
worksheet.Range(cellRange).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center
'Auto adjust the column widths
worksheet.Columns.AdjustToContents()
workbook.SaveAs("<filename>")
You can use EasyXLS to import the xlsx file and after that to apply the format that you need:
// Create an instance of the class that imports XLSX files
ExcelDocument workbook = new ExcelDocument();
// Import XLSX file
workbook.easy_LoadXLSXFile(filePath);
// Get the table of data from the first sheet
ExcelTable xlsTable = ((ExcelWorksheet)workbook.easy_getSheetAt(0)).easy_getExcelTable();
// Create the formatting style for cells
ExcelStyle xlsStyle = new ExcelStyle();
xlsStyle.setHorizontalAlignment(Alignment.ALIGNMENT_LEFT);
xlsStyle.setForeground(Color.DarkGray);
//Apply the formatting to A1 cell
xlsTable.easy_getCell(0, 0).setStyle(xlsStyle);
// Resave the XLSX file
workbook.easy_WriteXLSXFile(newFormattedFilePath);
Check this link on formatting Excel cells fro more specific details.
I have a macro-enabled Excel file "D:\MyTests\ExcelTests\template.xlsm" with no data in it, only the VBA code, and my C# code needs to output a workbook data over there. Normally I output workbook data like this:
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Add();
Excel.Worksheet worksheet = workbook.Sheets[1];
Excel.Worksheet worksheet2 = workbook.Sheets[2];
// populate worksheets with some data
DataTable2Worksheet(tableMain, worksheet, verSize);
DataTable2Worksheet(tableExtra, worksheet2, 0);
string fileName = #"D:\MyTests\ExcelTests\newFile";
if (File.Exists(fileName ))
{
File.Delete(fileName );
}
workbook.SaveAs(fileName);
workbook.Close();
Marshal.ReleaseComObject(application);
but this creates a new file (which cannot be macros enabled programmatically). If I want to output the workbook to existing file
string existingFile = #"D:\MyTests\ExcelTests\template.xlsm"
the method
workbook.SaveAs(existingFile );
won't work. So, what should I do instead? Thanks.
Save the file specifically in xlOpenXMLWorkbookMacroEnabled format:
string existingFile = #"D:\MyTests\ExcelTests\template.xlsm"
workbook.SaveAs(existingFile, 52);
I'm using VS2010 + Office Interop 2007 to attempt to get a few specific spreadsheet names from an Excel spreadsheet with 5-6 pages. All I am doing from there is saving those few spreadsheets I need in a tab delimited text file for further processing. So for the three spreadsheet names I get, each one will have its own tab delimited text file.
I can save a file as tab delimited just fine through Interop, but that's assuming I know what the given page name is. I have been informed that each page name will not follow a strict naming convention, but I can account for multiple names like "RCP", "rcp", "Recipient", etc when looking for a desired name.
My question is, can I get all spreadsheet page names in some sort of index so I may iterate through them and try to find the three names I need? That would be so much nicer than trying to grab "RCP", "rcp", "Recipient" pages via a bajillion try/catches.
I'm close, because I can get the COUNT of pages in an Excel spreadsheet via the following:
Excel.Application excelApp = new Excel.Application(); // Creates a new Excel Application
excelApp.Visible = true; // Makes Excel visible to the user.
// The following code opens an existing workbook
string workbookPath = path;
Excel.Workbook excelWorkbook = null;
try
{
excelWorkbook = excelApp.Workbooks.Open(workbookPath, 0,
false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true,
false, 0, true, false, false);
}
catch
{
//Create a new workbook if the existing workbook failed to open.
excelWorkbook = excelApp.Workbooks.Add();
}
// The following gets the Worksheets collection
Excel.Sheets excelSheets = excelWorkbook.Worksheets;
Console.WriteLine(excelSheets.Count.ToString()); //dat count
Thank you for your time.
foreach ( Worksheet worksheet in excelWorkbook.Worksheets )
{
MessageBox.Show( worksheet.Name );
}
You could use a dictionary:
Dictionary<string, Worksheet> dict = new Dictionary<string, Worksheet>();
foreach ( Worksheet worksheet in excelWorkbook.Worksheets )
{
dict.Add( worksheet.Name, worksheet );
}
// accessing the desired worksheet in the dictionary
MessageBox.Show( dict[ "Sheet1" ].Name );