How to save a .xltm file to .xlsm with OpenXML? - c#

Ive been using the OpenXmlPackage.SaveAs to save my template files in to excel (.xltx to .xlsx) But when it comes to a macro enabled .xltm the file gets corrupt when saving to .xlsm
I have been reading in the help sections for this API and various threads online but i couldnt find anything covering this so i could get it working.
//open the excel using openxml sdk
using (SpreadsheetDocument doc = SpreadsheetDocument.CreateFromTemplate(fileOpen))
{
doc.SaveAs(fileClose);
}
"Excel cannot open the file 'filename.xlsx' because the file format for the file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file."
Anyone out there that have a idea regarding this? Thanks in advance.

This would do the trick.
byte[] byteArray = File.ReadAllBytes(sDocpath + inputPath);
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(DocumentFormat.OpenXml.SpreadsheetDocumentType.MacroEnabledWorkbook);
}
File.WriteAllBytes(dirPath + outputPath, stream.ToArray());
}

Related

NPOI corrupting xlsm workbook

I am required to write some data into an macro enabled workbook which was developed in 1998, i am using NPOI dotnet core library for this task. I am able to write the values into the excel correctly, however i am seeing that alignment and formatting of the sheets is lost. Screenshots below:
First one shows the file after open the file using NPOI and downloading the same, and second shows the file when it is locally opened.
below is the code i am using
public XSSFWorkbook OpenExcelFile(string filePath, string tempSavePath)
{
using (var stream = new FileStream(tempSavePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
var temphssfwb = new XSSFWorkbook(OPCPackage.Open(filePath));
temphssfwb.Write(stream);
}
XSSFWorkbook hssfwb;
hssfwb = new XSSFWorkbook(OPCPackage.Open(tempSavePath));
hssfwb.CreateSheet("casevalidationsheet");
return hssfwb;
}
Can someone please help me understand why NPOI is ruining the alignment of my excel workbook?

Change the version of excel attached file in email using c#

I am trying to send the email with attached excel xlsx file.
I can download the attached excel file on my laptop, and galaxy phone but I can't download it on the iphone.
So I want to lower the excel version using https://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.xlfileformat.aspx.
For this, when I change the code to
wb.SaveAs("filename.xls", FileFormat: Microsoft.Office.Interop.Excel.XlFileFormat.xlExcel8);
It says SaveAs does not have a parameter for FileFormat.
They said they need 2 parameters. (Stream stream, bool validate)
So I have no idea where can I put those fileformat to change the fileformat from xlsx to xls on my code.
//set DataTable Name of Excel Sheet
data.TableName = "E_Data";
//Create a New Workbook
using (XLWorkbook wb = new XLWorkbook())
{
//Add the DataTable as Excel Workhseet
wb.Worksheets.Add(data);
using (MemoryStream memoryStream = new MemoryStream())
{
//Save the Excel Workbook to MemoryStream
wb.SaveAs(memoryStream);
//Convert MemoryStream to Byte array
byte[] bytes = memoryStream.ToArray();
memoryStream.Close();
...
mm.Attachments.Add(new Attachment(new MemoryStream(bytes), "NSOList.xlsx"));
}
}
You are using ClosedXml Libary, ClosedXML doesn't support the older format, hence you can not save your file as xls.
if you can use Microsoft.Office.Interop.Excel namespace (i.e office is installed on server \ pc) it will be very easy, create your excel file using Interop.Excel and than save it
using SaveAs() method for example: wb.SaveAs(c:\\memoryStream.xls,XlFileFormat.xlOpenXMLWorkbook)

Npoi xls file save corrupts excel file

So I am able to open and dig through an xls (Excel 97-2003) file. However, the problem is when I try to save it. After I save it, and it succeeds, I then go and manually open the Excel file and get an error saying that it cannot open the Excel file and that it is corrupt. This happens regardless of whether I make any changes or not.
I am still able to, within the program, open the excel file and read through the data.
I am using NPOI 2.2.1 and 2.3.0 (which I installed via Nuget). Both versions have the same results.
string excelLocation = settings.GetExcelDirectory() + week.ExcelLocation;
HSSFWorkbook wbXLS;
// Try to open and read existing workbook
using (FileStream stream = new FileStream(excelLocation, FileMode.Open, FileAccess.Read))
{
wbXLS = new HSSFWorkbook(stream);
}
ISheet sheet = wbXLS.GetSheet("Schedule");
using (FileStream stream = new FileStream(excelLocation, FileMode.Create, FileAccess.Write))
{
wbXLS.Write(stream);
}
Do you have multi-line cell contents (with a line break)?
I just came across such a problem with my column headers in row 0.
Excel encodes a line break by replacing it with _x000a_ (i.e. line1_x000a_line2), NPOI doesn't do that.
Tried with nuget 2.3.0 and xlsx file, but might also be helpful in your case.
I worked around (and verified the cause) by replacing line feeds before saving:
// Encode LineFeeds in column headers (row 0)
IRow rowColHeaders = sheet.GetRow(0);
foreach (ICell cell in rowColHeaders.Cells)
{
string content = cell.StringCellValue;
if (content.Contains("\n"))
cell.SetCellValue(content.Replace("\n", "_x000a_"));
}
try something like
FileStream sw = File.Create(excelLocation);
wbXLS.Write(sw);
sw.Close();

Saving an OpenXML Document (Word) generated from a template

I have a bit of code that will open a Word 2007 (docx) document and update the appropriate CustomXmlPart (thus updating the Content Controls in the document itself as they are mapped to the CustomXmlPart) but can't work out how to save this as a new file.! Surely it can't be that hard!
My current thinking is that I need to open the template and copy the content into a new, blank document - file by file, updating the CustomXmlPart when I encounter it.
Call me old fashioned but that sounds a little bit clunky to me!
Why can't I just do a WordprocessingDocument.SaveAs(filename); ...?
Please tell me I am missing something simple here.
Thanks in advance
Are you referring to the OpenXml SDK? Unfortunately, as of OpenXml SDK 2.0, there's no SaveAs method. You'll need to:
Make a temporary copy of your template file, naming it whatever you want.
Perform your OpenXml changes on the above file.
Save the appropriate sections (ie. using the .myWordDocument.MainDocumentPart.Document.Save() method for the main content or someHeaderPart.Header.Save() method for a particular header).
OpenXml 2.8.1 has a SaveAs method that seems to do the trick.
var document = WordprocessingDocument.Open(specificationPath, true);
document.SaveAs("filePath/documentCopy.docx");
Indeed you can, at least, in OpenXml SDK 2.5. However, watchout to work with a copy of the original file, because changes in the XML will be actually reflected in the file. Here you have the methods Load and Save of my custom class (after removing some validation code,...):
public void Load(string pathToDocx)
{
_tempFilePath = CloneFileInTemp(pathToDocx);
_document = WordprocessingDocument.Open(_tempFilePath, true);
_documentElement = _document.MainDocumentPart.Document;
}
public void Save(string pathToDocx)
{
using(FileStream fileStream = new FileStream(pathToDocx, FileMode.Create))
{
_document.MainDocumentPart.Document.Save(fileStream);
}
}
Having "_document" as a WordprocessingDocument instance.
You can use a MemoryStream to write the changes, rather than in the original file. Consequently, you can save that MemoryStream to a new file:
byte[] byteArray = File.ReadAllBytes("c:\\temp\\mytemplate.docx");
using (var stream = new MemoryStream())
{
stream.Write(byteArray, 0, byteArray.Length);
using (var wordDoc = WordprocessingDocument.Open(stream, true))
{
// Do work here
// ...
wordDoc.MainDocumentPart.Document.Save(); // won't update the original file
}
// Save the file with the new name
stream.Position = 0;
File.WriteAllBytes("C:\\temp\\newFile.docx", stream.ToArray());
}
In Open XML SDK 2.5 Close saves changes when AutoSave is true.
See my answer here:
https://stackoverflow.com/a/36335092/3285954

Read excel file from a stream

I need a way to read a Excel file from a stream. It doesn't seem to work with the ADO.NET way of doing things.
The scenario is that a user uploads a file through a FileUpload and i need to read some values from the file and import to a database.
For several reasons I can't save the file to disk, and there is no reason to do so either.
So, anyone know of a way to read a Excel file from a FileUpload stream?
It seems i found a soultion to the problem myself.
http://www.codeplex.com/ExcelDataReader
This library seems to work nicely and it takes a stream to read the excel file.
ExcelDataReader reader = new ExcelDataReader(ExcelFileUpload.PostedFile.InputStream);
This can be done easily with EPPlus.
//the excel sheet as byte array (as example from a FileUpload Control)
byte[] bin = FileUpload1.FileBytes;
//gen the byte array into the memorystream
using (MemoryStream ms = new MemoryStream(bin))
using (ExcelPackage package = new ExcelPackage(ms))
{
//get the first sheet from the excel file
ExcelWorksheet sheet = package.Workbook.Worksheets[1];
//loop all rows in the sheet
for (int i = sheet.Dimension.Start.Row; i <= sheet.Dimension.End.Row; i++)
{
//loop all columns in a row
for (int j = sheet.Dimension.Start.Column; j <= sheet.Dimension.End.Column; j++)
{
//do something with the current cell value
string currentCellValue = sheet.Cells[i, j].Value.ToString();
}
}
}
SpreadsheetGear can do it:
SpreadsheetGear.IWorkbook workbook = SpreadsheetGear.Factory.GetWorkbookSet().Workbooks.OpenFromStream(stream);
You can try it for yourself with the free evaluation.
Disclaimer: I own SpreadsheetGear LLC
Infragistics has an excel component that can read an excel file from a stream.
I'm using it in a project here and it works well.
Also the open source myXls component could easily be modified to support this. The XlsDocument contstructor only supports loading from a file given by a file name, but it works by creating a FileStream and then reading the Stream, so changing it to support loading from streams should be trivial.
Edit:
I see that you found a solution but I just wanted to note that I updated the source code for the component so that it now can read an excel file directly from a stream. :-)
I use ClosedXML nuget package to read excel content from stream. It has a constructor overload in XLWorkbook class which takes stream pointing to an excel file (aka workbook).
imported namespace at the top of your code file:
using ClosedXML.Excel;
Source code:
var stream = /*obtain the stream from your source*/;
if (stream.Length != 0)
{
//handle the stream here
using (XLWorkbook excelWorkbook = new XLWorkbook(stream))
{
var name = excelWorkbook.Worksheet(1).Name;
//do more things whatever you like as you now have a handle to the entire workbook.
var firstRow = excelWorkbook.Worksheet(1).Row(1);
}
}

Categories

Resources