I need to retrieve time values from an Excel file.
Here is the structure of the document :
ID | COLUMN_1 | COLUMN_2
1 | 00:10:00 | 00:08:23
2 | 00:23:00 | 01:45:00
3 | 02:01:45 | 01:23:35
...
So my Excel workbook contains few time columns (formatted as "Hour") but when I change the format to "Standard" it displays float numbers.
I created a script using C# to read this document.
I need to copy the content of the column as a Time to another Excel file.
The script processes all columns and it populates another Excel workbook, but the INSERT doesn't work because it tries to insert a float to a time field.
How to get a Time value ?
foreach (DataRow row in rawDataTable.Rows)
{
// INSERT INTO ....
row[1] // Time column. How to get a Time value ?
// I retrieved something like 0,00684027777777778, I need something formatted as HH:mm:ss
// Because I need to copy the Time value to a Time field in another Excel workbook.
}
Excel date values are in days since 1/1/1900, so if you have a time value without date, you can multiply it by 86400 to get the seconds.
But if you want to copy a cell formatted as time between workbooks, you don't have to convert it, just copy it as a double and format the cell correctly.
Let me try to answer your question. The key of saving data is to format it, like #grahamj42 said.
Basically, I created one button. On click handler I read data from source Excel app and I save it to newly created target Excel app. I included notes so it is pretty clear.
You have to include at the top of page these directives:
using System.Reflection;
using Excel = Microsoft.Office.Interop.Excel;
Here is complete code:
public class ExcelRow
{
public int ID { get; set; }
public string Date1 { get; set; }
public string Date2 { get; set; }
}
protected void btnCopy_Click(object sender, EventArgs e)
{
//source excel app
var sourceExcelApp = new Excel.Application()
{
Visible = false,
ScreenUpdating = false,
DisplayAlerts = false
};
//get source workBook - assuming that path of source excel file is in C:\\
Excel.Workbook sourceWorkbook = sourceExcelApp.Workbooks.Open(#"c:\\source.xls",
Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value, Missing.Value);
//assuming that data is inside of first worksheet (WorkSheets[1])
Excel._Worksheet sourceWorksheet = (Excel._Worksheet)sourceWorkbook.Worksheets[1];
//get column ranges including header names
Excel.Range ID = sourceWorksheet.Range["A1"];
Excel.Range date1 = sourceWorksheet.Range["B1"];
Excel.Range date2 = sourceWorksheet.Range["C1"];
//get last row in table(from A1 to last cell in C column)
int lastRowCount = sourceWorksheet.UsedRange.Rows.Count;
var excelRow = new ExcelRow();
List<ExcelRow> excelRowList = new List<ExcelRow>();
//note that we start iteration from 1 in order not to read first cells values
for (int i = 1; i < lastRowCount; i++)
{
excelRowList.Add(new ExcelRow
{
ID = int.Parse(ID.Offset[i, 0].Value2.ToString()),
Date1 = date1.Offset[i, 0].Value2.ToString(),
Date2 = date2.Offset[i, 0].Value2.ToString()
});
}
//create new instance of target Excel app and
var targetExcelApp = new Excel.Application();
targetExcelApp.Visible = true;
Excel.Workbook targetWorkbook = targetExcelApp.Workbooks.Add();
Excel._Worksheet targetWorksheet = (Excel._Worksheet)targetExcelApp.ActiveSheet;
//set columns headers titles
targetWorksheet.Cells[1, "A"] = "ID";
targetWorksheet.Cells[1, "B"] = "COLUMN_1";
targetWorksheet.Cells[1, "C"] = "COLUMN_2";
//formating target rows
targetWorksheet.Range[String.Concat("B1:", "B", lastRowCount)].NumberFormat = "#";
targetWorksheet.Range[String.Concat("C1:", "C", lastRowCount)].NumberFormat = "#";
//fill targeted rows
int counter = 1;
foreach (var row in excelRowList)
{
counter++;
targetWorksheet.Cells[counter, "A"] = row.ID;
targetWorksheet.Cells[counter, "B"] = row.Date1;
targetWorksheet.Cells[counter, "C"] = row.Date2;
}
//autofit columns width
targetWorksheet.Columns.AutoFit();
//save data to new excel app
targetWorksheet.SaveAs("target", Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
//release resources
ReleaseObject(sourceWorksheet);
ReleaseObject(sourceWorkbook);
ReleaseObject(sourceExcelApp);
ReleaseObject(targetWorksheet);
ReleaseObject(targetWorkbook);
ReleaseObject(targetExcelApp);
}
And this is method for relasing excel resources:
public static void ReleaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
finally
{
GC.Collect();
}
}
Related
I have more than 100 excel files.My job is to merge to all the excel files into one excel. I did easily by writing the C# program for merging excels. Now I need to Identify the records as per the excel file name.I mean I need to add the actual Excel file name to the new columns for all rows exists.
For Example:
I have excel Dom.xls having 2 rows in that excel.
Name SSN Address
1 0923 1 winter st
2 0924 2 winter st
Now I need the excel should create new column named"Excel File Name"
and should write the file name like beow
Name SSN Address Excel File Name
1 0923 1 winter st dom.xls
2 0924 2 winter st dom.xls
How Do I achieve this.
Either I need this requirement before merging all the excels or after merging the excels.
Below code I used to merge all excels.
class Program
{
static void Main(string[] args)
{
MergeExcel.DoMerge(new string[]
{
#"C:\Users\dom\Desktop\Reim Account\032 - dom_AMESBURY.xlsx",
#"C:\Users\dom\Desktop\Reim Account\128 - dom_BRAINTREE.xlsx",
#"C:\Users\dom\Desktop\Reim Account\960 - dom_RETIREMENT.xlsx"....etc
},
#"D:\MyExcel\dom.xlsx", "V", 2);
}
}
public class MergeExcel
{
Excel.Application app = new Microsoft.Office.Interop.Excel.ApplicationClass();
//initialize the object of saved target
Excel.Workbook bookDest = null;
Excel.Worksheet sheetDest = null;
//initialize the object of read data
Excel.Workbook bookSource = null;
Excel.Worksheet sheetSource = null;
string[] _sourceFiles = null;
string _destFile = string.Empty;
string _columnEnd = string.Empty;
int _headerRowCount = 0;
int _currentRowCount = 0;
public MergeExcel(string[] sourceFiles, string destFile, string columnEnd, int headerRowCount)
{
//Use class Missing case to indicate the missing value. e.g. when you call the method that has default parameter value
bookDest = (Excel.WorkbookClass)app.Workbooks.Add(Missing.Value);
sheetDest = bookDest.Worksheets.Add(Missing.Value, Missing.Value, Missing.Value, Missing.Value) as Excel.Worksheet;
sheetDest.Name = "Data";
_sourceFiles = sourceFiles;
_destFile = destFile;
_columnEnd = columnEnd;
_headerRowCount = headerRowCount;
}
//open worksheet
void OpenBook(string fileName)
{
bookSource = app.Workbooks._Open(fileName, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
sheetSource = bookSource.Worksheets[1] as Excel.Worksheet;
}
//close worksheet
void CloseBook()
{
bookSource.Close(false, Missing.Value, Missing.Value);
}
//copy table header
void CopyHeader()
{
Excel.Range range = sheetSource.get_Range("A1", _columnEnd + _headerRowCount.ToString());
range.Copy(sheetDest.get_Range("A1", Missing.Value));
_currentRowCount += _headerRowCount;
}
//copy data
void CopyData()
{
int sheetRowCount = sheetSource.UsedRange.Rows.Count;
Excel.Range range = sheetSource.get_Range(string.Format("A{0}", _headerRowCount), _columnEnd + sheetRowCount.ToString());
range.Copy(sheetDest.get_Range(string.Format("A{0}", _currentRowCount), Missing.Value));
_currentRowCount += range.Rows.Count;
}
//save the result
void Save()
{
bookDest.Saved = true;
bookDest.SaveCopyAs(_destFile);
}
//exit the process
void Quit()
{
app.Quit();
}
void DoMerge()
{
//declare variate bool to judge if copy table header
bool b = false;
foreach (string strFile in _sourceFiles)
{
OpenBook(strFile);
if (b == false)
{
CopyHeader();
b = true;
}
CopyData();
CloseBook();
}
Save();
Quit();
}
/// merge table
/// source file
/// object file
/// the sign of the last column
/// the number of rows of table header
public static void DoMerge(string[] sourceFiles, string destFile, string columnEnd, int headerRowCount)
{
new MergeExcel(sourceFiles, destFile, columnEnd, headerRowCount).DoMerge();
}
}
You could do something like this in CopyData. Send the filename to CopyData void CopyData(string strFile). Then after range.Copy add the following lines.
Excel.Range range_name = sheetDest.get_Range(string.Format("E{0}", _currentRowCount), string.Format("E{0}", _currentRowCount + sheetRowCount));
range_name.Value = strFile;
This will add the filename to column E. Maybe some tweaking is necessary since I'm not that familiar with Excel Interop.
I am reading an Excel sheet programmatically using Microsoft.Office.Interop.Excel in C#.
I am able to read it row by row and converting each row to a string arrray. Then, I am adding these rows to a DataTable.
Every thing works fine except the one of the column in the Excel contains Date values, and when I fetch it from the Excel Range object and cast it to string array, the date values gets converted to some sort of decimal numbers.
For e.g.-
If the date value is '6/4/2016 8:14:39 PM', I get the value as '42522.5224305556'
If the date value is '5/27/2016 1:10:12 PM', I get the value as '42517.54875'
Below is my code-
private System.Data.DataTable GetTicketsFromExcel(string excelFilePath)
{
System.Data.DataTable dtblTickets = new System.Data.DataTable();
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Worksheet ws = new Worksheet();
Workbook wb = null;
try
{
wb = excelApp.Workbooks.Open(excelFilePath, Type.Missing, Type.Missing,
Type.Missing, Type.Missing,
Type.Missing, Type.Missing,
Type.Missing, Type.Missing,
Type.Missing, Type.Missing,
Type.Missing, Type.Missing,
Type.Missing, Type.Missing);
ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets.get_Item(1);
Range usedRange = ws.UsedRange;
Range rowRange;
string[] lsRow = null;
for (int i = 1; i <= usedRange.Columns.Count; i++)
{
dtblTickets.Columns.Add(usedRange.Cells[5, i].Value.ToString());
}
string sortColumn = "Reported On";
string sortDirection = "DESC";
dtblTickets.Columns[sortColumn].DataType = typeof(DateTime);
for (int row = 6; row <= usedRange.Rows.Count; row++)
{
//dtblTickets.Columns.Add()
rowRange = usedRange.Rows[row];
object[,] cellValues = (object[,])rowRange.Value2;
lsRow = cellValues.Cast<object>().Select(o => Convert.ToString(o)).ToArray<string>();
dtblTickets.Rows.Add(lsRow.ToArray());
}
dtblTickets.DefaultView.Sort = sortColumn + " " + sortDirection;
dtblTickets = dtblTickets.DefaultView.ToTable();
}
catch (Exception ex)
{
}
finally
{
wb.Close();
excelApp.Quit();
Marshal.ReleaseComObject(ws);
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(excelApp);
ws = null;
wb = null;
excelApp = null;
}
return dtblTickets;
}
Please note-
I don't want to use OLEDB to read and export this
I want to able to read the Excel row by row (without extracting each cell value and converting them)
I don't want to convert/format the original Excel document data
Can someone please help me with this?
Not quite sure, if you want to solve the problem this way, but one way is to change the property of the Cells (or the whole row or column) in Excel.
Right click on a Cell
Format Cells
Under "Number" select Category "Text" for the Cells.
I've tested it and it worked.
I'm trying to compare a cell with a string to replace it if it is equal. But when I try to do the code below the 0x800A03EC error occurs.
int cont = 0;
string cell;
do
{
cont++;
cell = rCol.ToUpper() + cont.ToString(); // = "D1"
string cellData = ((Excel.Range)sheet.Cells[cell]).Value2.ToString();
if (cellData == from)
{
sheet.Cells[cell] = to;
}
} while (sheet.Cells[cell] == null);
How can I do this?
If you know the cell you want to check, for example A1, you can do it like this:
using System;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
namespace Test
{
class Program
{
static void Main(string[] args)
{
// create app
var excelApp = new Excel.Application();
// open workbook
var workbook = excelApp.Workbooks.Open(
#"C:\Users\Home\Documents\Book1.xlsx",
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing);
// open sheet
var sheet = (Excel.Worksheet)workbook.Sheets[1];
// create some variables
var from = "Pete";
var to = "Dave";
// compare cell A1 [1,1] with 'from'
if (string.Equals(sheet.Cells[1,1].Value, from))
{
sheet.Cells[1, 1].Value = to;
}
// save the workbook
workbook.Save();
// close the workbook and release resources
workbook.Close(true, workbook.Path);
Marshal.ReleaseComObject(workbook);
workbook = null;
}
}
}
Try this to get at a simple range:
int row = 1;
string col = "D";
string text = sheet.get_Range(col + row.ToString()).Value;
The 0x800A03EC error is a value returned by Excel, which means NAME_NOT_FOUND (see this SA question). Looks like you were passing a parameter that Excel could not find, probably because you were passing a string ("D1"), rather than two integer parameters (4,1).
It's impossible to tell where you are getting the rCol.ToUpper() value, without seeing more of your code. However, if you are attempting to go through a series of columns and rows to check for an equality condition (that's what it looks like you are attempting), you will quickly run into the pesky problem of how to increment the column value using capital letters (just try it; not much fun!).
One solution I did in VB recently was to use the native Excel function index, which uses numeric values to get at a particular cell. You would need to cast an object of the type Excel.WorksheetFunction to use that function. But I have since discovered there are easier solutions than using an Excel function:
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
namespace exceltest
{
class Program
{
static void Main(string[] args)
{
Microsoft.Office.Interop.Excel.Application xl = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook workbook = xl.Workbooks.Open(#"C:\test.xlsx");
Microsoft.Office.Interop.Excel.Worksheet sheet = workbook.Sheets[1];
xl.Visible = true;
//use this if you want to use native Excel functions (such as index)
Microsoft.Office.Interop.Excel.WorksheetFunction wsFunc = xl.WorksheetFunction;
int maxNum = 100; // set maximum number of rows/columns to search
string from = "blah";
string to = "blum";
//this is pretty slow, since it has to interact with 10,000 cells in Excel
// just one example of how to access and set cell values
for (int col = 1; col <= maxNum; col++)
{
for (int row = 1; row <= maxNum; row ++)
{
Range cell = (Range)sheet.Cells[row, col];
if ((string)cell.Value == from) //cast to string to avoid null reference exceptions
{
cell.Value = to;
}
}
}
}
}
}
I have this code that export an excel file using c# from 1 listview. My problem now is if I have 2 listviews that will be generated in 1 excel file, my plan is listview1 is for sheet1 and listview2 is for sheet2.
this is my code generates listview1 to excel into sheet1:
string[] st = new string[listView1.Columns.Count];
DirectoryInfo di = new DirectoryInfo(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\");
if (di.Exists == false)
di.Create();
fileName f = new fileName();
if (f.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\" + f.Filenam + ".xls", false);
sw.AutoFlush = true;
string header = "";
for (int col = 0; col < listView1.Columns.Count; col++)
{
header += listView1.Columns[col].Text.ToString() + "\t";
}
sw.Write(header);
int rowIndex = 1;
int row = 0;
string st1 = "";
for (row = 0; row < listView1.Items.Count; row++)
{
if (rowIndex <= listView1.Items.Count)
rowIndex++;
st1 = "\n";
for (int col = 0; col < listView1.Columns.Count; col++)
{
st1 = st1 + listView1.Items[row].SubItems[col].Text.ToString() + "\t";
}
sw.Write(st1);
}
sw.Close();
FileInfo fil = new FileInfo(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\" + f.Filenam + ".xls");
if (fil.Exists == true)
MessageBox.Show("Process Completed", "Export to Excel", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
I have used EPPlus, its free, give performance benefits, and provides many Excel functions. Other option you can look for is Microsoft InterOp for Excel export, but it has performance problems.
As Irfan already mentioned, you could do that with Microsoft.Office.Interop
Excel.Application xlsApp = new Excel.Application();
Excel.Workbook workbook;
workbook = xlsApp.Workbooks.Open(configuration.XLSExportedFile, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
foreach (Excel.Worksheet sheet in workbook.Sheets)
{
workbook.Activate();
sheet.Activate();
}
That would help you to step through all your sheets in your Excel file.
Now in case you want to expand it with multiple sheets, you can read C# how to add Excel Worksheet programmatically Office XP / 2003 in order to find how to add additional sheets.
What you could do now, is put your text into a variable for example HTML or any kind of information from your listbox.
string html = Clipboard.GetText(TextDataFormat.Html);
Now you can play around with the Clipboard(alternative solution, but to avoid).
Clipboard.SetText(html);
It actually enters information into your Clipboard, what you could do is pass all your listbox values into the Clipboard.
And now the final step would be to paste it at the position that you want.
sheet.Range(cellmapp).PasteSpecial();
Where cellmap is supposed to be for example A1. In case your text that you have in your listbox is too long you can adapt your rows/columns.
//Auto fits all columns and rows
//https://stackoverflow.com/questions/14748322/c-sharp-autofit-method-for-excel-sheet
sheet.Columns.AutoFit();
sheet.Rows.AutoFit();
Don't forget, if you work with COM processes, close every object and file.
workbook.SaveAs(configuration.XLSExportedFile);
workbook.Close();
xlsApp.Quit();
xlsApp.Dispose();
I don't say that would be the best solution to do, but you could look up for OpenXML also.
I've used ClosedXML before, the syntax is really clean and simple and you can get this sort of task done in just a few lines
This block shows how to add a list to a new sheet and save it
List<string> list = new List<string>();
var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Sample Sheet");
worksheet.Cell(1, 1).Value = list;
workbook.SaveAs("HelloWorld.xlsx");
i have 2 issues what i am facing
i have an dataset where i need to send the data from dataset to an
excel once data in dumped in that location.
i need to change the column headers make them bold
2:
Above the report headers we should pass 1 parameter that will be the name(Employee details) from c# we need to pass as an parameter to it.
it can change what ever parameter we pass it on.
ex:
Reportname: Employee details
Name EmpID city
Arun 11 bangalore
Kiran 56 chennai
Rahul 23 pune
The following should work, but I did not test it. Thank you to Deborah Kurata for writing a large part of the code below.
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
private void ExportToExcel(DataTable Table, string ReportName, string Filename)
{
Excel.Application oXL;
Excel.Workbook oWB;
Excel.Worksheet oSheet;
Excel.Range oRange;
// Start Excel and get Application object.
oXL = new Excel.Application();
// Set some properties
oXL.Visible = true;
oXL.DisplayAlerts = false;
// Get a new workbook.
oWB = oXL.Workbooks.Add(Missing.Value);
// Get the active sheet
oSheet = (Excel.Worksheet)oWB.ActiveSheet ;
oSheet.Name = "Report";
int rowCount = 3;
foreach (DataRow dr in Table.Rows)
{
for (int i = 1; i < Table.Columns.Count+1; i++)
{
// Add the header the first time through
if (rowCount==3)
{
oSheet.Cells[1, i] = Table.Columns[i - 1].ColumnName;
rowCount++;
}
oSheet.Cells[rowCount, i] = dr[i - 1].ToString();
}
rowCount++;
}
// Resize the columns
oRange = oSheet.get_Range(oSheet.Cells[3, 1],
oSheet.Cells[rowCount, Table.Columns.Count]);
oRange.EntireColumn.AutoFit();
// Set report title *after* we adjust column widths
oSheet.Cells[1,1] = ReportName;
// Save the sheet and close
oSheet = null;
oRange = null;
oWB.SaveAs(Filename, Excel.XlFileFormat.xlWorkbookNormal,
Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Excel.XlSaveAsAccessMode.xlExclusive,
Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value);
oWB.Close(Missing.Value, Missing.Value, Missing.Value);
oWB = null;
oXL.Quit();
// Clean up
// NOTE: When in release mode, this does the trick
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}