is it possible to edit .xlsm files using NPOI with C# - c#

Thanks for the help from people on this site, I was able to modify .xlsx file using NPOI. Code is below, but my final goal is to be able to modify .xlsm file cell value. Is there a way to do this? I tried to run with the following code but after won't be able to open the file once i ran the program.
XSSFWorkbook templateWorkbook;
using (FileStream fs = new FileStream(#"C:\Users\jzhu\Desktop\FlexTimeSheetTest.xlsm", FileMode.Open, FileAccess.ReadWrite))
{
templateWorkbook = new XSSFWorkbook(fs);
fs.Close();
}
XSSFSheet sheet = (XSSFSheet)templateWorkbook.GetSheet("Sheet1");
sheet.GetRow(0).GetCell(0).SetCellValue("Drago");
sheet.ForceFormulaRecalculation = true;
File.Delete(#"C:\Users\jzhu\Desktop\FlexTimeSheetTest.xlsm");
using (FileStream file = new FileStream(#"C:\Users\jzhu\Desktop\FlexTimeSheetTest.xlsm", FileMode.CreateNew, FileAccess.Write))
{
templateWorkbook.Write(file);
file.Close();
}

Update your NPOI library to latest version (2.1.3.1 at present time).
Using this version, your code and sample xlsm file with one macro recorded - I got valid file after modifying it by your code.
Excel is able to open it, and macro can be run.

XSSFWorkbook xlWorkbook;
using (FileStream file = new FileStream(toEditFile,FileMode.Open, FileAccess.Read))
{
xlWorkbook = new XSSFWorkbook(file);
}
var xlWorksheet = xlWorkbook.GetSheet(#"sheet");
// do stuff
using (FileStream file = new FileStream(toEditFile, FileMode.Create, FileAccess.Write))
{
xlWorkbook.Write(file);
file.Close();
}

Related

Saving an ExcelPackage with exclusive lock of excel, giving error after opening excel file - C# - EPPlus

My objective is to write some data into an excel.
Here i am opening a file with file stream by exclusive lock (FileMode.Open, FileShare.Read etc., I need to lock the file to restrict others writing into excel while i am processing.) then writing some content into it and finally close the stream, so that other threads can write into this file. I am using EPPlus(5.7.4) version.
The code i am using here is :
public void WriteToExcel()
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
using (var excelPackage = new ExcelPackage(stream))
{
DoSomething(excelPackage);
excelPackage.SaveAs(stream);
stream.Close();
}
}
public void DoSomething(ExcelPackage excelPackage)
{
var cell = excelPackage.Workbook.Worksheets[0].Cells[2, 3];
cell.Value = "some value";
}
I put a break point in using statement and opened excel in the middle of execution and it showing a message saying like below which is correct.
But once i finish with execution when i try to open excel file it showing below error message.
We found a problem with some content in Sample.xlsx. Do you want us to try to recover as much as we can? if you trust the source of this book, Click Yes
I tried in different ways but none worked for me, as same error message is displaying. Can someone help me resolving this issue.
The problem is that you're reading from and rewriting to the same file stream simultaneously.
You can test this by changing excelPackage.SaveAs(new FileInfo("Book2.xlsx")); and create a new file - your file will be created without any issues.
You could open your original document, write the changes to a new file, then delete the original file and rename the new file back to the original name:
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (var stream = new FileStream("Book1.xlsx", FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
using (var excelPackage = new ExcelPackage(stream))
{
DoSomething(excelPackage);
excelPackage.SaveAs(new FileInfo("Book2.xlsx"));
}
File.Delete("Book1.xlsx");
File.Move("Book2.xlsx", "Book1.xlsx");
The caveat with this is that if you have multiple things trying to access that file, then they might throw FileNotFound exceptions if they happen to try to open Book1.xlsx after it's delete and before Book2.xlsx is renamed.
That said, if you're dealing with that level of parallelism then you shouldn't be using a Excel file.
Side note: You don't need stream.Close(); as the using block automatically closes the stream.
Below code useful to me, you can refer it.
public void WriteToExcel()
{
string path = #"C:\Use**op\aa.xlsx";
FileInfo file = new FileInfo(path);
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (ExcelPackage package = new ExcelPackage(file))
{
DoSomething(package);
}
}
public void DoSomething(ExcelPackage package)
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
worksheet.Cells[2,4].Value = "some value";
package.Save();
}

Excel byte[] (OLE) to xls c#

I'm trying to parse a .xls document that is saved in a SQL database using VB for Access. It's saved as an OLE document.
What I do is write the document using a binary writer
FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite);
BinaryWriter bw = new BinaryWriter(fs, document.GetTextEncoding());
bw.Write(document);
bw.Close();
fs.Close();
So, the file is saved but when I open it on Office365 it gives me a grey page:
But, Windows explorer preview shows the document!!!!
I've tryed to open file and save with Microsoft Interop but I got the same results. I've tryed to copy to a new file with HSSFWorkbook but the same ocurrs. With .doc, .jpg , .pdf I first try to allocate the header in the file to get the start position for the binary writer but I cannot figure out if .xls has this kind of header. (Most of those .pdf, .doc, .jpg document can be opened)
This is Interop code:
excel.Workbooks.Open(filePath, Notify: false, CorruptLoad: Microsoft.Office.Interop.Excel.XlCorruptLoad.xlRepairFile).
SaveAs(filePath, Microsoft.Office.Interop.Excel.XlFileFormat.xlExcel5, Type.Missing, Type.Missing, true, false, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, XlSaveConflictResolution.xlLocalSessionChanges, Type.Missing, Type.Missing);
Have tryed changing the XLFileFormat, even sometimes I can't preview it.
HSSF code:
HSSFWorkbook hssfwb;
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
hssfwb = new HSSFWorkbook(file);
file.Close();
}
FileStream file2 = new FileStream(filePath+ "_mod", FileMode.Create, FileAccess.Write);
hssfwb.Write(file2);
file2.Close();
Happens the same, can preview but can't open.
EDIT
document:
byte[] doc = (byte[])reader["DEX_Documento"];
It's read from database, it's a hex string parsed to byte. Unfortunately, is hard to find a document that I can give you the string due to legal terms.
Also, I can read the rows with the HSSF solution, but the problem persists.
So I finally found a library without using Office that works.
Spire.Xls.Workbook wbFromStream = new Spire.Xls.Workbook();
FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read);
wbFromStream.LoadFromStream(file);
wbFromStream.SaveToFile(filePath+".xls", Spire.Xls.ExcelVersion.Version2013);
file.Close();

Error while importing xlsx file uisng NPOI while it works for xls

I am trying to import an excel file (xlsx) but it throws the following question :
Could not load file or assembly 'ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73' or one of its dependencies. The system cannot find the file specified.
But it works perfectly fine for xls with the same code.
using (FileStream file = new FileStream(filename, FileMode.Open,
FileAccess.Read))
{
FileExtension = Path.GetExtension(filename);
if
(FileExtension.ToLower().Equals(StringConstants.FILE_EXTENSION_XLS))
{
HSSFWorkBook = new HSSFWorkbook(file);
intCountSheets = HSSFWorkBook.NumberOfSheets;
EaRepos = DiagFunAnaClass.EaRepos;
objPackage = DiagFunAnaClass.objPackage;
plantCode = DiagFunAnaClass.plantCode;
buttonValidate.Enabled = true;
}
else if
(FileExtension.ToLower().Equals(StringConstants.FILE_EXTENSION_XLSX))
{
XSSFWorkBook = new XSSFWorkbook(file);
The error comes in the last line of the above code.
I tried below code and it is not throwing any exception:
string filename = #"D:\test.xlsx";
using (FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
string FileExtension = Path.GetExtension(filename);
if (FileExtension.ToLower().Equals(".xls"))
{
var HSSFWorkBook = new HSSFWorkbook(file);
int CountSheets = HSSFWorkBook.NumberOfSheets;
}
else if (FileExtension.ToLower().Equals(".xlsx"))
{
var XSSFWorkBook = new XSSFWorkbook(file);
}
}
I think there may be two reasons for the error you encounter:
The file you are trying to access is open. You should close the file from all the editors and try again.
The version of NPOI that I am using is 2.3.0. You may be using older version.
your code seems to be correct and I also tried the Manprit's code. It is working correctly in my version 2.2.1. Sometime in NPOI functionality doesn't work even you are following everything as per documentation. Last thing I can suggest you is try typecasting the filestream type for XSSF with Stream type like below
var XSSFWorkBook = new XSSFWorkbook((Stream)file);
FileStream is derived from Stream class

Problematic corruption of .xlsx files with NPOI - Excel cannot open the file 'file.xlsx" because the file format or file extension is not valid

When reading or modifying some user-created .xlsx files, I get the following error message:
We found a problem with some content in 'test.xlsx'. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes.
Clicking Yes gets me another message:
Excel cannot open the file 'test.xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file.
Example of a problem .xlsx file here (before put in NPOI).
Here's the same file, now corrupted after being read from and written back with iWorkbook.Write(filestream); here.
I have no issues creating a new .xlsx file with the following code:
string newPath = #"C:\MyPath\test.xlsx";
using (FileStream fs = new FileStream(newPath, FileMode.Create, FileAccess.Write))
{
IWorkbook wb = new XSSFWorkbook();
wb.CreateSheet();
ISheet s = wb.GetSheetAt(0);
IRow r = s.CreateRow(0);
r.CreateCell(0);
ICell c = r.GetCell(0);
c.SetCellValue("test");
wb.Write(fs);
fs.Close();
}
That works fine.
Even opening one of the problem child .xlsx files, setting it to an IWorkbook and writing it back to the file works:
string newPath = #"C:\MyPath\test.xlsx";
using (FileStream fs = new FileStream(newPath, FileMode.Open, FileAccess.ReadWrite))
{
IWorkbook wb = new XSSFWorkbook(fs);
wb.Write(fs);
fs.Close();
}
However, after running through code that reads from it, gets ISheets, IRows, ICells, etc.... it corrupts the .xlsx file. Even though I specifically removed anything that modifies the workbook. No Creates, Sets, Styles, etc. with NPOI.
I can't really include my code because it would just be confusing, but for the sake of completeness I'm really only using the following types and functions from NPOI during this test:
IWorkbook
XSSFWorkbook
ISheet
IRow
ICell
.GetSheetAt
.GetRow
.GetCell
.LastRowNum
So one of those causes corruption. I would like to eventually set values again and get it working like I have for .xls.
Has anyone experienced this? What are some NPOI functions that could cause corruption? Any input would be appreciated.
Edit: Using NPOI v2.2.1.
I think the problem is that you are reading from, and writing to, the same FileStream. You should be doing the read and write using separate streams.
Try it like this:
string newPath = #"C:\MyPath\test.xlsx";
// read the workbook
IWorkbook wb;
using (FileStream fs = new FileStream(newPath, FileMode.Open, FileAccess.Read))
{
wb = new XSSFWorkbook(fs);
}
// make changes
ISheet s = wb.GetSheetAt(0);
IRow r = s.GetRow(0) ?? s.CreateRow(0);
ICell c = r.GetCell(1) ?? r.CreateCell(1);
c.SetCellValue("test2");
// overwrite the workbook using a new stream
using (FileStream fs = new FileStream(newPath, FileMode.Create, FileAccess.Write))
{
wb.Write(fs);
}
I had the same problem. In my case the problem was not with the NPOI itself but with its dependency, SharpZipLib.
I used NPOI 2.3.0 and SharpZipLib 1.0.0. and it was given the the same error as in your case. The generated Excel was 0 bytes in size.
I downgraded the SharpZipLib back to 0.86.0 in the project where I was using the NPOI (a Service layer) and also in the MVC project(I had the package of SharpZipLib here too).
I also removed manually in web.config the assembly dependency previously created for SharpZipLib:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
.......
<dependentAssembly>
<assemblyIdentity name="ICSharpCode.SharpZipLib" publicKeyToken="1b03e6acf1164f73" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.999" newVersion="1.0.0.999" />
</dependentAssembly>
</assemblyBinding>
I hope this helps someone.
I had the same error attempting to write the excel file to a memory stream and then downloading through my .net Core controller.
This code was my problem (At this point, workbook contained the NPOI excel file I created):
var fileName = $"export.xlsx";
var mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
MemoryStream stream = new();
workbook.Write(stream);
byte[] output = stream.GetBuffer();
return File(output, mimeType, fileName);
The issue was this line:
byte[] output = stream.GetBuffer();
That line gave me a byte array that contained the contents of my excel file, but I did not realize that the GetBuffer returned not only the byte array representing the excel file, but also the remaining allocated memory for the byte array.
I replaced that line with this:
byte[] output = stream.ToArray();
and life was good.
When writing back to the file, be sure to use Create as FileMode method. If you use Open, the file will be corrupted because it will concatenate the new file at the end of the old one.
IWorkbook workbook;
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
workbook = new XSSFWorkbook(file);
}
// do things to workbook...
using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(file);
}

Editing and saving xlsx with NPOI results in a corrupted file

FileStream s = new FileStream(#myPath, FileMode.Open, FileAccess.ReadWrite);
IWorkbook wb = new XSSFWorkbook(s);
s.Close();
ISheet isheet = wb.GetSheetAt(0);
IRow irow = isheet.CreateRow(0);
irow.CreateCell(0).SetCellValue("foo");
s = new FileStream(#myPath + "blah.xlsx", FileMode.Create);
wb.Write(s);
s.Close();
New file is created but corrupted. I've seen people say this is fixed in version 2.0.6, but still not working for me.
Looks like you are using #myPath as the share / file name on line 1 of your code to create a Stream, yet you concatenate a file name onto #myPath to save the file. Could this be the source of the error?

Categories

Resources