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.
Related
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.
}
As per the title I am trying to save and retrieve .xlsx files (as well as any other formats the user may upload) to a SQL database and then retrieve them to be opened in the native application.
I have the code that I am currently trying to get to work. I have narrowed it down to the saving and loading of the byte[]. I can't seem to find a good way to do this in c#.
Below is what I have but it just opens the file and I get a message "Excel cannot open the file "Book1.xlsx" because the file format or extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file."
Note: The code below works fine with images and other formats.
private byte[] _fileArray;
private static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
public MainWindow()
{
InitializeComponent();
using (Stream stream = File.OpenRead(#"C:\Users\user\Desktop\Book1.xlsx"))
{
stream.Seek(0, SeekOrigin.Begin);
_fileArray = ReadFully(stream);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var newFolder = System.IO.Directory.CreateDirectory(System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString()));
string tempFileName = System.IO.Path.Combine(newFolder.FullName, "Book1.xlsx");
using (FileStream stream = File.Create(tempFileName))
{
FileInfo tempFile = new FileInfo(tempFileName) { Attributes = FileAttributes.Temporary /* optimises by holding in memory*/ };
stream.Write(_fileArray, 0, _fileArray.Length);
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = tempFileName;
//proc.StartInfo.Arguments = "";
proc.Start();
proc.Close();
}
}
Thanks in advance.
I am using below code to create and it will show user prompt to user whether the user can able to save or open or cancel a excel file.....
I am successfully able to download the file but I need to zip before it is showing user prompt, Later zip file will be showed to the user like with options open or save or cancel.....
How can I do that with not using any other third party library and using Microsoft own Gzip DLL?
The below code is for exporting to excel functionality:
public ActionResult ExportToExcel()
{
byte[] file;
string targetFilename = string.Format("{0}-{1}.xlsx", "Generated", "excel");
DataTable dt = common.CreateExcelFile.ListToDataTable(GetSearchDraftPRResults());
common.CreateExcelFile excelFileForExport = new CreateExcelFile();
file = excelFileForExport.CreateExcelDocumentAsStream(dt, targetFilename);
Response.Buffer = true;
return File(file, "application/vnd.ms-excel", targetFilename);
}
Would anyone please help on this how to zip a file before it is showing to user?
Many thanks in advance.....
Modified Code:
public ActionResult ExportToExcel()
{
byte[] file;
string targetFilename = string.Format("{0}-{1}.xlsx", "Generated", "excel");
DataTable dt = common.CreateExcelFile.ListToDataTable(GetSearchDraftPRResults());
common.CreateExcelFile excelFileForExport = new CreateExcelFile();
file = excelFileForExport.CreateExcelDocumentAsStream(dt, targetFilename);
Response.Buffer = true;
byte[] zipFile = Compress(file);
return File(file, "application/vnd.ms-excel", targetFilename);
}
public byte[] Compress(FileInfo fileToCompress)
{
using (FileStream originalFileStream = fileToCompress.OpenRead())
{
if ((System.IO.File.GetAttributes(fileToCompress.FullName) & FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".gz")
{
using (FileStream compressedFileStream = System.IO.File.Create(fileToCompress.FullName + ".gz"))
{
using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
{
originalFileStream.CopyTo(compressionStream);
}
}
}
MemoryStream mem = new MemoryStream();
CopyStream(originalFileStream, mem);
return mem.ToArray();
}
}
public static void CopyStream(Stream input, Stream output)
{
byte[] b = new byte[32768];
int r;
while ((r = input.Read(b, 0, b.Length)) > 0)
output.Write(b, 0, r);
}
Check out the SharpZipLib library. It works very well and is free to use even in commercial applications.
You can use JZlib from JCraft. Very easy to use, compression declaration can look like this, the code inside depends on what's you doing but you can find working example in JZlib examples:
public byte[] compress(byte[] buf, int start, int[] len) {
...
}
I use Interop to SaveAs(D:/Temp) a template excel sheet after the changes are made.
Then I use FileStream to send the user a Pop-up to save this file. But that file in D:\Temp still exists.
Is there a way to delete this file on Pop-up response?
//Save the Excel File
SaveExcelFile(exportPath, sourceFile, excelWorkBook,
excelApllication, excelWorkSheet);
#region Pop Up and File Open
if (System.IO.File.Exists(sourceFile))
{
FileStream fsSource =
new FileStream(sourceFile, FileMode.Open, FileAccess.Read);
return File(fsSource, "application/vnd.ms-excel", "FileName" + .xls");
}
else
{
return View();
}
#endregion
To delete one file
string filePath)= #"C:\MyDir\filename.txt";
public bool RemoveFile(string filePath)
{
try
{
if (File.Exists(filePath))
{
File.Delete(filePath);
return true;
}
else
return true;
}
catch (Exception ex)
{
return false;
}
}
Delete all files
string[] filePaths = Directory.GetFiles(#"c:\MyDir\");
foreach (string filePath in filePaths)
File.Delete(filePath);
To delete all files using one code line
Array.ForEach(Directory.GetFiles(#"c:\MyDir\"),
delegate(string path) { File.Delete(path); });
You can use File.Delete method.
if (File.Exists("File_Path"))
{
File.Delete("File_Path");
}
Updated
For downloading binary files,
using (FileStream fs = File.OpenRead(path))
{
int length = (int)fs.Length;
byte[] buffer;
using (BinaryReader br = new BinaryReader(fs))
{
buffer = br.ReadBytes(length);
}
Response.Clear();
Response.Buffer = true;
Response.AddHeader("content-disposition", String.Format("attachment;filename={0}", Path.GetFileName(path)));
Response.ContentType = "application/" + Path.GetExtension(path).Substring(1);
Response.BinaryWrite(buffer);
Response.Flush();
Response.End();
}
Found this code from here
Instead of creating a temp file, loading it to stream, and then trying to delete it, I suggest that you create the file directly in memory stream (i.e. System.IO.MemoryStream) in the first place, so you don't have to load it and delete it.
If you cannot create it directly in memory stream, the main issue is that you cannot delete the temp file while you're using it in the FileStream. In this case, you copy the FileStream to a MemoryStream, close and dispose the FileStream, delete the temp file, and then return the MemoryStream to the user.
You can use the function bellow to copy streams correctly.
// Author: Racil Hilan.
/// <summary>Copies data from a source stream to a target stream.</summary>
private static void CopyStream(Stream SourceStream, Stream TargetStream) {
const int BUFFER_SIZE = 4096;
byte[] buffer = new byte[BUFFER_SIZE];
//Reset the source stream in order to process all data.
if (SourceStream.CanSeek)
SourceStream.Position = 0;
//Copy data from the source stream to the target stream.
int BytesRead = 0;
while ((BytesRead = SourceStream.Read(buffer, 0, BUFFER_SIZE)) > 0)
TargetStream.Write(buffer, 0, BytesRead);
//Reset the source stream and the target stream to make them ready for any other operation.
if (SourceStream.CanSeek)
SourceStream.Position = 0;
if (TargetStream.CanSeek)
TargetStream.Position = 0;
}
You can use File.Delete() for this. Just make sure you've closed the stream before you try to delete the file, and preferably, that you have been able to send whatever you need to.
I'm guessing you don't want to delete the file if the main operation fails.
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);
}