I am using Asp.Net MVC application, Visual Studio 2013, SQL Server Data base
There is a particular location in my system's local drive i.e., c:/Files/Exim_Files/ , where a lot of excel(.xlsx) files are sitting.
I want to get the particular file from that location and save it programmatically (without Save pop up) in same location with same/different name. while saving the excel data should not be lost, file should be as it is, just I need to save/SaveAs it again.
How can I achieve this requirement?
Note that I am using Virtual Machine and inside Virtual Machine: Microsoft Office is not installed. So the code will have to work without Microsoft Office installation in the machine. I can only use Microsoft Office in my host machine.
Edit
In below code, I am using Aspose.Cells to save the Excel file from 1 location to another.
I am getting the particular File from sharedLocation in array "l_strFileUploadPath" and then checking, if the file that I am getting from user exists in shared location, then I want to save/SaveAs that
file into different location (defined in 'string str') along with entire data (say I want to import the data as well while Saving the Excel in different location).
The issue I am facing is that, the file that is getting saved in C: drive, is not saving the data which is present inside the Excel. It seems it is creating a new excel file in c: drive with same name (x-TECHNICAL_DIT_BUDV01_RV124_R01_2015_Test.xlsx) having 2 sheets.
1 is 'sheet 1' and another is 'Evaluation Warning' sheet.
How can I remove the 'Evaluation Warning' sheet and what is the method of saving the exact file (along with data) from shared drive to c: drive, as per my code.
This is the first time using Aspose.Cells to get and Save/SaveAs the file from 1 location to another.
protected void getFileAndSave()
{
string[] l_strFileUploadPath = Directory.GetFiles("//181.184.11.435/share//Temp/New folder");
foreach (var filename in l_strFileUploadPath)
{
string fileName = Path.GetFileName(filename);
string p_filename = "x-TECHNICAL_DIT_Test.xlsx"; //this is the file I am getting from user
if (fileName == p_filename)
{
//-- Using Aspose.Cells
Workbook wb = new Workbook();
Worksheet worksheet = wb.Worksheets["Sheet1"];
worksheet.Name = "Technical Data";
//Save workbook with export cell as true
OoxmlSaveOptions opts = new OoxmlSaveOptions();
opts.ExportCellName = true;
wb.Save(str + file, opts);
}
}
}
It seems for me that you just want to copy the file.
Take a look at File.Copy()
File.Copy(#"c:\excel.xsl", #"c:\other\excel.xsl");
EDIT for comment:
I think it will be hard to change app.xml metadata without just manually looking what changes are made there during save/saveAs and then trying to understand how to copy this behavior and change it programmatically inside that file.
Related
I want a method to write the datatable data to .xls,.xlsx or.csv based on the input provided along with the delimiter as input
public class DataTableExtensions
{
/*Input Params : Datatable input
fileFormat(.xls,.csv,.xlsx)
delimeter('\t' (tabSpace) or ,(comma) or | (pipe Symbol)
filepath - Any local folder*/
public void WriteToCsvFile(DataTable dataTable,string fileFormat,string delimeter, string filePath)
{
//Code to convert file based on the input
//Code to create file
System.IO.File.WriteAllText(filePath, fileContent.ToString());
}
}
You said it is only 1000 rows every 2 hours in the comments. That is a acceptable amount of data for a C# programm. I would say the big question left is wich output format you use.
.CSV is the simplest one. This format can be done with a File.WriteLine() and some string concaction. There is no build in CSV parser or writer code I am aware off in C#, but there is plenty of 3rd party code.
.XLS requires the (t)rusty Office COM Interop. That requires office to be installed and does not work from a non-interactive session (like a Windows Service). On top of all the normal issues for using COM interop.
There is the odd "export to XLS" function on existing classses, but those are rare, far inbetween and about everything you get. Unfortunately as we always had COM Interop as fallback, we never quite developed a standalone library for working with .XLS. Ironically working with this old format is harder from C#/.NET then it would be from Java.
.XLSX however is easier. It can be written using the OpenXML SDK. Or the XML writer and ZipArchive class: At their core all the ???x formats are a bunch of .XML files in a renamed .ZIP container. There should even be 3rd party code out there to make using the SDK easier.
.CSV is the lowest common denominator and propably the easiest to create. However if a user is supposed to open this document, the lack for formating might become an issue.
.XSLX would be my choice if you need a user to open it.
.XSL I would avoid like a swarm of angry bees.
I have written this Program to convert Xls,XLSx using console application with
Datatable as input and for text file I have written a simple stream writer logic.This works good. Initially I have installed package manage console and below code
using expertXLs package.I am not sure wheather I can share the key of that
or not.Please search the key and give in config before running it
Package Manage Console - Install-Package ExpertXls.ExcelLibrary -Version 5.0.0
Code :
--------
private static void GenerateTxtFileFromDataTable(DataTable sampleDataTable,string delimiter)
{
var _expertxlsLK = ConfigurationManager.AppSettings["ExpertxlsLK"];
//GetKey Value from config
// Create the workbook in which the data from the DataTable will be loaded 0 for 2003 Excel(xls),1 for 2007 Excel(xlsx)
ExcelWorkbookFormat workbookFormat = ExcelWorkbookFormat.0;
// create the workbook in the desired format with a single worksheet
ExcelWorkbook workbook = new ExcelWorkbook(workbookFormat);
workbook.EnableFormulaCalculations();
workbook.LicenseKey = _expertxlsLK;
// get the first worksheet in the workbook
ExcelWorksheet worksheet = workbook.Worksheets[0];
// set the default worksheet name
worksheet.Name = "ClaimInformation";
// load data from DataTable into the worksheet
worksheet.LoadDataTable(sampleDataTable, 1, 1, true);
worksheet.Workbook.EnableFormulaCalculations();
workbook.Save(#"M:\Rupesh\test.xlsx");
workbook.Close();
}
I am generating several excel copies from a template (its really big).
For that First I am taking the template from a file location, then based on a loop for every iteration I am creating a new ExcelPackage(newFile,Template).
After that I am taking the exact ExcelWorksheet that I have to edit.
Then after editing I am Saving as the file as newFile. The time of opening the saved file Two problem is occurring:
If there is no Excel instance is running on the PC then the saved file is opening but with no data.
If the Excel instance is running then the saved file is opening with Warning message but working. "Problem with some content with Excel. Do you want us to recover?" and "Excel was able to recover some unreadable content "
string templateExcel = #"Location\template.xlsx";
FileInfo templateFile = new FileInfo(#"Location\newFile.xlsx");
using (FileStream templateExcelStream = File.OpenRead(templateExcel))
{
using (ExcelPackage copyExcel = new ExcelPackage(templateExcelStream))
{
ExcelWorksheet presentWorkSheet = copyExcel.Workbook.Worksheets["Name"];
presentWorkSheet.Cells[4, 2].Value = Value from condition;
copyExcel.SaveAs(templateFile);
}
}
Thanks all of you for your valuable time. I got the solution.
For me the issue was in the template itself as it contained invalid references to lookup tables. I found this in Formula -> Name Manager.
I suggest that you check the template if you face this issue.
I currently have a program that merges a folder consisting of word docs into one combined file via user input with a FileBrowserDialog. Once files are selected, a 'combine' button applies the code shown below which sources the folder containing the documents, output location and name of the file created.
string fileDate = DateTime.Now.ToString("dd-MM-yy");
string fileTime = DateTime.Now.ToString("HH.mm.ss");
string outcomeFolder = outputFolder;
string outputFileType = ".docx";
string outputFile = "Combined Folder " + fileDate + " # " + fileTime + outputFileType;
string outputFileName = Path.Combine(outcomeFolder, outputFile);
// Combines the file name, output path selected and the yes / no for pagebreaks.
MsWord.Merge(sourceFiles, outputFileName, pageBreaker);
// Message displaying how many files are combined.
MessageBox.Show("A total of " + sourceFiles.Length.ToString() + " documents have been merged", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);}
The MsWord referenced calls a separate .CS file which combines the folder components, output name and a boolean to enable page-breaks. The MsWord also automatically saves the word .doc to the user specified location once the contents of the folder are successfully combined. MsWord.Merge(sourceFiles, outputFileName, pageBreaker);
The issue i'm wanting to address is, when I enable this check box:
if (convert2PDFBox.Checked)
Microsoft.Office.Interop.Word.Application officeApp = new Microsoft.Office.Interop.Word.Application();
officeApp.Documents.Open(outputFileName);
outputFileType = ".pdf";
officeApp.ActiveDocument.SaveAs(outputFileName + outputFileType, WdSaveFormat.wdFormatPDF);
officeApp.Quit();
I want the program to solely create a PDF of the combined folder and not 2 seperate .doc and .PDF files, which it currently does. Since the MsWord.save function is called separately and is essential to the overall function of my program, I was wondering is there a possibility of deleting the initially combined file once conversion of the PDF takes place? e.g. "combinedDocument".Delete - Essentially allowing the copy to take place however not presenting the user with the initial .doc - only the .PDF
Though the issue is small, I would love to get it addressed and welcome any suggestions or advice with this manner. I can also provide any additional information if needed, thank you.
tl;dr - merging program creates an amalgamated Word .doc, which i want to change solely to a PDF when a checkbox is enabled instead of creating a .doc and PDF.
I finally resolved my issue - What I decided to do was manipulate my existing MsWord.cs and create a separate PDF.cs call for my main form:
Rather than save the Word .doc when being merged, I instead used: wordApplication.ActiveDocument.SaveAs(outputFile, Word.WdSaveFormat.wdFormatPDF);
which saved the merged content thus far as a .pdf
This however presented errors with Microsoft Word as I was then prompted to 'Save File As' due to the merged file never actually being saved in a .Doc / .Docx format
I then altered the closing statement of the call,
// Close Word application
wordApplication.Quit(
false, // save changes
By setting the 'Save Changes' setting to False, it removed the 'Save As' prompt which allowed the Word doc. to be dismissed without needing to be saved, thus leaving only the initial PDF created. I then applied the two separate File type calls to each checkbox presented, which allowed the user to enable the outcome format of the merged files.
Thank you for the suggestions regarding the issue.
I'm using C# to convert the .doc to .pdf. The .doc is on the vendor's site. To get the .doc, we have to click on a button which presents us with option to Open, Save, or Cancel. When the user clicks on Save button, it prompts for the location. The user chooses the location in mapped drive, say, S:\Some Folder\abc.doc, and the actual folder location is \\server\\folder\Some Folder. This is where my program comes in to play. I'm using FileSystemWatcher class in c# with Filter set for .doc files. I can see in debug that the file is found. The folder location is hardcoded and saved as the actual folder location mentioned above. The user and the application has full permission to the folder. However, I'm getting FileNotFoundException when I run the program.
This is what I have
WriteToFile("Starting Word application");
Application word = new Application();
object missing = Type.Missing;
var sourcefile = new FileInfo(path);
// check if the created file ends with .doc.
System.Diagnostics.Debug.WriteLine(path);
if (!path.ToLower().EndsWith(".doc"))
{
return "";
}
word.Visible = false;
WriteToFile("Opening doc as read only");
// open readonly
System.Diagnostics.Debug.WriteLine(sourcefile.FullName);
var doc = word.Documents.Open(FileName: sourcefile.FullName, ReadOnly: true);
The strange thing is sourcefile.FullName doesn't show the hard coded server address that path is set to. It shows the file path as S:\Some Folder\abc.doc, which makes no sense to me. What's going on here, and why can't it find the file?
The OnCreate event can fire when the underlying file is still in use/being written to which can cause problems if you immediately try to access it.
The simple solution is to introduce either an arbitrary delay to allow for the file to be closed by the process creating it, or better a loop with a short delay that attempts to access the file, catches the relevant exception should it occur and retries.
My guess is that you use the wrong FileInfo object. Try to generate an new one or use
System.IO.Path.Combine(#"\\server\folder\Some Folder", "sourcefile.Name")
which you could also use to generate your new FileInfo Object. The object which you are using is probably the one of the user dialogue box which is using the mapped drive. You do also have a typo in your location. \\SERVERNAME\\ isn't an UNC path. There should be only two backslashes on the beginning of the string. It should be
#"\\server\folder\Some Folder"
WriteToFile("Starting Word application");
Application word = new Word.Application();
object missing = Type.Missing;
var sourcefile = new System.IO.FileInfo(path);
string SomeShare = #"\\SomeServer\Someshare\Somepath";
System.IO.FileInfo WorkFile = new System.IO.FileInfo(System.IO.Path.Combine(SomeShare, sourcefile.Name));
// check if the created file ends with .doc.
System.Diagnostics.Debug.WriteLine(path);
if (!path.ToLower().EndsWith(".doc"))
{
return "";
}
word.Visible = false;
WriteToFile("Opening doc as read only");
// open readonly
System.Diagnostics.Debug.WriteLine(sourcefile.FullName);
var doc = word.Documents.Open(FileName: WorkFile.FullName, ReadOnly: true);
}
This works just fine for me, it updates the path to the correct UNC pattern. If the file still isn't accesible you should check if you can open it on the workstation using the UNC path you have generated.
I am having an xml file like:
<CurrentProject>
// Elements like
// last opened project file to reopen it when app starts
// and more global project independend settings
</CurrentProject>
Now I asked myself wether I should deliver this xml file with above empty elements with the installer for my app or should I create this file on the fly on application start if it does not exist else read the values from it.
Consider also that the user could delete this file and that should my application not prevent from working anymore.
What is better and why?
UPDATE:
What I did felt ok for me so I post my code here :) It just creates the xml + structure on the fly with some security checks...
public ProjectService(IProjectDataProvider provider)
{
_provider = provider;
string applicationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
_projectPath = Path.Combine(applicationPath,#"TBM\Settings.XML");
if (!File.Exists(_projectPath))
{
string dirPath = Path.Combine(applicationPath, #"TBM");
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
using (var stream = File.Create(_projectPath))
{
XElement projectElement = new XElement("Project");
projectElement.Add(new XElement("DatabasePath"));
projectElement.Save(stream, SaveOptions.DisableFormatting);
}
}
}
In a similar scenario, I recently went for creating the initial file on the fly. The main reason I chose this was the fact that I wasn't depending on this file being there and being valid. As this was a file that's often read from/written to, there's a chance that it could get corrupted (e.g. if the power is lost while the file is being written).
In my code I attempted to open this file for reading and then read the data. If anywhere during these steps I encountered an error, I simply recreated the file with default values and displayed a corresponding message to the user.