how to close File Stream in C# - c#

Please see this code.
string name = dt.Rows[0]["Name"].ToString();
byte[] documentBytes = (byte[])dt.Rows[0]["DocumentContent"];
int readBytes = 0;
//int index = 0;
readBytes = documentBytes.Length;
try
{
using (FileStream fs = new FileStream(name, FileMode.Create, FileAccess.Write, FileShare.Read))
{
fs.Write(documentBytes, 0, readBytes);
//System.Diagnostics.Process prc = new System.Diagnostics.Process();
//prc.StartInfo.FileName = fs.Name;
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
app.Visible = false;
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Open(fs.Name);
Microsoft.Office.Interop.Excel._Worksheet worksheet = (Excel.Worksheet)workbook.Sheets[1]; // Explicit cast is not required here
// lastRow = worksheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell).Row;
app.Visible = true;
fs.Flush();
fs.Close();
}
}
catch (Exception ex)
{
MessageBox.Show("You have clicked more than one time. File is already open.", "WorkFlow", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
I am opening an excel file using the file stream. Excel is showing up nicely. But I am not able to close file stream. It still comes with a small pop up that shows 'File Now available'. How to get rid of that? I can see fs.Close() and Flush() really not working here. Please help.

You're asking Excel to open the file while you still have the stream open. Given that you're just trying to write bytes to it, I'd just use:
// This will close the file handle after writing the data
File.WriteAllBytes(name, documentBytes);
// Then you're fine to get Excel to open it
var app = new Microsoft.Office.Interop.Excel.Application();
app.Visible = false;
var workbook = app.Workbooks.Open(name);

Related

Cannot edit generated excel file

Problem:
In installed Office 2010 computer, my app have to copy an empty excel file (file A) to new excel file (file B) and use OpenXML library (V2.5) to execute some action, finally saved to hard disk. After that I open file B and just add a litle bit data (for example: 1) to it and save and close it.
when I reopen file B, excel thrown an error: Excel found unreadable content in ' file B' do you want to recover the contents of this workbook... and I can not open it.
Below is my code:
static void Main(string[] args)
{
ExportDataSet(#"C:\A.xlsx",#"C:\");
}
public static void Copy(String oldPath, String newPath)
{
FileStream input = null;
FileStream output = null;
try
{
input = new FileStream(oldPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
output = new FileStream(newPath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
var buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
}
}
catch (Exception e)
{
}
finally
{
if (input != null)
{
input.Close();
input.Dispose();
}
if (output != null)
{
output.Close();
output.Dispose();
}
}
}
public static string ExportDataSet(string filePath, string path, int startRow = 10)
{
var pathToSave = path;
if (!Directory.Exists(pathToSave))
Directory.CreateDirectory(pathToSave);
var filename = pathToSave + Guid.NewGuid() + Path.GetExtension(filePath);
Copy(filePath, filename);
var fs = File.Open(filename, FileMode.Open);
{
using (var myWorkbook = SpreadsheetDocument.Open(fs, true))
{
var workbookPart = myWorkbook.WorkbookPart;
var Sheets = myWorkbook.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
var relationshipId = Sheets.First().Id.Value;
var worksheetPart = (WorksheetPart)myWorkbook.WorkbookPart.GetPartById(relationshipId);
var sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
workbookPart.Workbook.Save();
//workbookPart.Workbook.CalculationProperties = new CalculationProperties() { FullCalculationOnLoad = true };
}
fs.Close();
fs.Dispose();
return filename;
}
}
I think the OpenXML library has something wrong.
Do you have any ideas? please share to me, thank you so much.
Remarks:
1. the computer use Office 2010 to open Excel file
2. the file format is Excel workbook (.xlsx)
3. if the computer installed office with later version (2013, 2016), the problem was not appeared.
Your buffer reading and writting logic is wrong. The second parameter is where it starts to read or write and you are passing it a zero value, so second iteration of the while is overwritting the content written in the first iteration thus you are getting corrupted data if the files are greater than your buffer size.
Your code should be similar to this:
var buffer = new byte[32768];
int totalRead = 0; // Variable to track where to write in the next while iteration
int read;
while ((read = input.Read(buffer, totalRead, buffer.Length)) > 0)
{
output.Write(buffer, totalRead, read);
totalRead += read; // Add to totalRead the amount written so next iteration does append the content at the end.
}

Getting a corrupted XLS file using NPOI

I tried to debug this code, but I didn't manage. Do any of you have any idea why my script creates a corrupted XLS file?
string strCaleSalvareTest = #"C:\Users\andrei.tudor\Documents\TipMacheta.xls";
HSSFWorkbook wbXLS;
strEr = "Er";
try
{
fsXLSCitire = new FileStream(strCaleSalvareTest, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
wbXLS = new HSSFWorkbook(fsXLSCitire);
strEr = string.Empty;
}
catch (Exception ex)
{
strEr = ex.Message;
}
When I try to run this, it jumps from wbXLS creation to the catch exception block.
You're getting an exception because you are creating a new FileStream for writing (FileAccess.Write) and passing it to the constructor of HSSFWorkbook which is expecting to be able to read from the stream. The file is corrupt because the FileStream is creating the file, but nothing is ever written to it.
If you're just trying to create a new blank workbook and save it to a file, you can do that as shown below. Note that you need to add at least one worksheet to the new workbook, or you will still generate a corrupt file.
// Create a new workbook with an empty sheet
HSSFWorkbook wbXLS = new HSSFWorkbook();
ISheet sheet = wbXLS.CreateSheet("Sheet1");
// Write the workbook to a file
string fileName = #"C:\Users\andrei.tudor\Documents\TipMacheta.xls";
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
wbXLS.Write(stream);
}
If you're trying to read an existing workbook OR create a new one if it doesn't exist, you need to do something like this:
string fileName = #"C:\Users\andrei.tudor\Documents\TipMacheta.xls";
HSSFWorkbook wbXLS;
try
{
// Try to open and read existing workbook
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
wbXLS = new HSSFWorkbook(stream);
}
}
catch (FileNotFoundException)
{
// Create a new workbook with an empty sheet
wbXLS = new HSSFWorkbook();
wbXLS.CreateSheet("Sheet1");
}
ISheet sheet = wbXLS.GetSheetAt(0); // Get first sheet
// ...
// Write workbook to file
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
wbXLS.Write(stream);
}

update existing workbook using epplus C#

I am trying to add new worksheet into existing workbook, code runs fine without any error. But changes are not being updated to the excel file.
Here is my code
string path = "C:\\TestFileSave\\ABC.xlsx";
FileInfo filePath = new FileInfo(path);
if (File.Exists(path))
{
using(ExcelPackage p = new ExcelPackage())
{
using(stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
{
p.Load(stream);
ExcelWorksheet ws = p.Workbook.Worksheets.Add(wsName + wsNumber.ToString());
ws.Cells[1, 1].Value = wsName;
ws.Cells[1, 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
ws.Cells[1, 1].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(184, 204, 228));
ws.Cells[1, 1].Style.Font.Bold = true;
p.Save();
}
}
}
The stream object is not tied to the package. The only relationship is it copies its bytes in your call to Load afterwards they are separate.
You do not need to even use a stream - better to let the package handle it on its own like this:
var fileinfo = new FileInfo(path);
if (fileinfo.Exists)
{
using (ExcelPackage p = new ExcelPackage(fileinfo))
{
//using (stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
{
//p.Load(stream);
ExcelWorksheet ws = p.Workbook.Worksheets.Add(wsName + wsNumber.ToString());
ws.Cells[1, 1].Value = wsName;
ws.Cells[1, 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
ws.Cells[1, 1].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(184, 204, 228));
ws.Cells[1, 1].Style.Font.Bold = true;
p.Save();
}
}
}
Here I have shown to write data into exiting excel file by creating a new sheet in same file. To answer your question: try using last two lines File.WriteAllBytes instead of p.Save().
string strfilepath = "C:\\Users\\m\\Desktop\\Employeedata.xlsx";
using (ExcelPackage p = new ExcelPackage())
{
using (FileStream stream = new FileStream(strfilepath, FileMode.Open))
{
p.Load(stream);
//deleting worksheet if already present in excel file
var wk = p.Workbook.Worksheets.SingleOrDefault(x => x.Name == "Hola");
if (wk != null) { p.Workbook.Worksheets.Delete(wk); }
p.Workbook.Worksheets.Add("Hola");
p.Workbook.Worksheets.MoveToEnd("Hola");
ExcelWorksheet worksheet = p.Workbook.Worksheets[p.Workbook.Worksheets.Count];
worksheet.InsertRow(5, 2);
worksheet.Cells["A9"].LoadFromDataTable(dt1, true);
// Inserting values in the 5th row
worksheet.Cells["A5"].Value = "12010";
worksheet.Cells["B5"].Value = "Drill";
worksheet.Cells["C5"].Value = 20;
worksheet.Cells["D5"].Value = 8;
// Inserting values in the 6th row
worksheet.Cells["A6"].Value = "12011";
worksheet.Cells["B6"].Value = "Crowbar";
worksheet.Cells["C6"].Value = 7;
worksheet.Cells["D6"].Value = 23.48;
}
//p.Save() ;
Byte[] bin = p.GetAsByteArray();
File.WriteAllBytes(#"C:\Users\m\Desktop\Employeedata.xlsx", bin);
}
I originally got the error code "A disk error occurred during a write operation. (Exception from HRESULT: 0x8003001D (STG_E_WRITEFAULT)) " from using this, but later learned that it was because the existing Excel file that I wanted to modify wasn't fully MS-Excel format compliant. I created thee original excel file in Open office as an .xls file, but EPPlus was not able to read it. When I regenerated this original excel file in Online Excel, everything worked fine.

Load excel file from resources/assembly in C#

I need to load an Excel file and write on it. I have already added the file to resources and set its build action to Embedded Resource. My problem is I can't seem to load it from the resources/assembly. I currently have this code:
Assembly assembly = Assembly.GetExecutingAssembly();
Assembly asm = Assembly.GetExecutingAssembly();
string file = string.Format("{0}.UTReportTemplate.xls", asm.GetName().Name);
var ms = new MemoryStream();
Stream fileStream = asm.GetManifestResourceStream(file);
xlWorkBook = xlApp.Workbooks.Open(file);
if (xlApp == null)
{
MessageBox.Show("Error: Unable to create Excel file.");
return;
}
xlApp.Visible = false;
What am I doing wrong? How can I access the file? Any help would be appreciated. Thanks.
You need to extract the resource (in this case an excel spreadsheet) from the assembly and write it as a stream to a File, eg:
Assembly asm = Assembly.GetExecutingAssembly();
string file = string.Format("{0}.UTReportTemplate.xls", asm.GetName().Name);
Stream fileStream = asm.GetManifestResourceStream(file);
SaveStreamToFile(#"c:\Temp\Temp.xls",fileStream); //<--here is where to save to disk
Excel.Application xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(#"c:\Temp\Temp.xls");
if (xlWorkBook == null)
{
MessageBox.Show("Error: Unable to open Excel file.");
return;
}
//xlApp.Visible = false;
...
public void SaveStreamToFile(string fileFullPath, Stream stream)
{
if (stream.Length == 0) return;
// Create a FileStream object to write a stream to a file
using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length))
{
// Fill the bytes[] array with the stream data
byte[] bytesInStream = new byte[stream.Length];
stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
// Use FileStream object to write to the specified file
fileStream.Write(bytesInStream, 0, bytesInStream.Length);
}
}
//save resource to disk
string strPathToResource = #"c:\UTReportTemplate.xls";
using (FileStream cFileStream = new FileStream(strPathToResource, FileMode.Create))
{
cFileStream.Write(Resources.UTReportTemplate, 0, Resources.UTReportTemplate.Length);
}
//open workbook
Excel.Application xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(strPathToResource);
if (xlWorkBook == null)
{
MessageBox.Show("Error: Unable to open Excel file.");
return;
}
xlApp.Visible = false;
I would like to add my code snippet here, which works well in Visual Studio 2015. (Just improved Jeremy Thompson's answer.)
(Don't forget to set the Excel file resource's Build Action Property to Embedded Resource in Property Window.)
public void launchExcel()
{
String resourceName = "Sample.xls";
String path = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
Assembly asm = Assembly.GetExecutingAssembly();
string res = string.Format("{0}.Resources." + resourceName, asm.GetName().Name);
Stream stream = asm.GetManifestResourceStream(res);
try
{
using (Stream file = File.Create(path + #"\" + resourceName))
{
CopyStream(stream, file);
}
Process.Start(path + #"\" + resourceName);
}catch (IOException ex)
{
MessageBox.Show(ex.Message);
}
}
public void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[8 * 1024];
int len;
while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, len);
}
}
Hope this will help you with your trouble.
Best regards.

Problems with releasing an object and closing a spreadsheet?

I am using EPPlus to open a spreadsheet and then populate it with pictures and information.
When i try to delete a folder containing all the pictures i used to populate my spreadsheet i get the error that this file is in use with another application. What would be the correct way to release the objects used and close the spreadsheet?
using (var package = new ExcelPackage(existingFile))
{
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
int i = 0;
foreach(ExcelWorksheet worksheet in workBook.Worksheets)
{
xlWorkSeet1[i] = worksheet;
i = i + 1;
}
}
}
//More code ...
FileStream aFile = new FileStream(tempFolderPathAlt + saveas + ".xls", FileMode.Create);
byte[] byData = package.GetAsByteArray();
aFile.Seek(0, SeekOrigin.Begin);
aFile.Write(byData, 0, byData.Length);
aFile.Close();
xlWorkSeet1 = null;
workBook = null;
}//End using
String P = Path.Combine(tempFolderPathAlt, "ExtractedFiles");
bool directoryExists = Directory.Exists(P);
if (directoryExists)
Directory.Delete(P, true); // deletes sub-directories
The error i get is when it is trying to delete a photo i added to my spreadsheet.
Try out following and please let me know whether this helps
int writeTimeout = 200;
using (var aFile = new FileStream(tempFolderPathAlt + saveas + ".xls", FileMode.Create))
{
aFile.WriteTimeout = writeTimeout;
byte[] byData = package.GetAsByteArray();
aFile.Seek(0, SeekOrigin.Begin);
aFile.Write(byData, 0, byData.Length);
xlWorkSeet1 = null;
workBook = null;
Thread.Sleep(writeTimeout);
}

Categories

Resources