Export Datatable to Excel File (.XLSX) - c#

I use this code to export Datatable to excel file (.xlsx)
Dim attachment As String = "attachment; filename=Excel.xlsx"
Response.ClearContent()
Response.AddHeader("content-disposition", attachment)
Response.ContentType = "application/vnd.ms-excel"
Dim tab As String = ""
For Each dc As DataColumn In dt.Columns
Response.Write(tab + dc.ColumnName)
tab = vbTab
Next
Response.Write(vbLf)
Dim i As Integer
For Each dr As DataRow In dt.Rows
tab = ""
For i = 0 To dt.Columns.Count - 1
Response.Write(tab & dr(i).ToString())
tab = vbTab
Next
Response.Write(vbLf)
Next
Response.End()
When I download the file I get This message :
"Excel cannot open the file 'Excel.xlsx' because the file format or file extension is not valid "
I use Excel 2010
Any Ideas why ?!

Your are creating a TSV - tab separated value.
Instead .xlsx try using .tsv

If you want to export as excel, maybe you can the third-party lib NPOI to make a excel object.

Related

How to split multiple lines in a cell

I'm trying to write a program that will allow me to read Excel files using C#.
These Excel files can contain information that has been entered with the use of "Alt-Enter" to create multiple lines within the cell. Each line denotes a different value.
How do I separate out the multiple values in the single cell?
Sample program:
Add a reference to Microsoft.Office.Interop
using Microsoft.Office.Interop.Excel;
string path = "C:\\Test.xlsx ";
Application excel = new Application();
Workbook wb = excel.Workbooks.Open(path);
Worksheet excelSheet = wb.ActiveSheet;
// Read the second row second column cell
string test = excelSheet.Cells[2, 2].Value.ToString();
string splittedString = test.Split('\n');

Leading 0 is dropped from excel data cells populated from VB

In my vb Windows Application Program I use this code to create excel report:
Public Sub CreateExcelFile(ByVal InputDataTable As DataTable, ByVal FileName As String)
Dim ExcelApp As New Microsoft.Office.Interop.Excel.ApplicationClass
Dim ExcelWorkbook As Microsoft.Office.Interop.Excel.Workbook = Nothing
Dim ExcelWorkSheet As Microsoft.Office.Interop.Excel.Worksheet = Nothing
Dim ColumnIndex As Integer = 0
Dim RowIndex As Integer = 1
Try
ExcelWorkbook = ExcelApp.Workbooks.Add()
ExcelWorkSheet = ExcelWorkbook.ActiveSheet()
For Each c As DataColumn In InputDataTable.Columns
ColumnIndex += 1
ExcelApp.Cells(RowIndex, ColumnIndex) = c.ColumnName
Next
For Each r As DataRow In InputDataTable.Rows
RowIndex += 1
ColumnIndex = 0
For Each c As DataColumn In InputDataTable.Columns
ColumnIndex += 1
ExcelApp.Cells(RowIndex, ColumnIndex) = r(c.ColumnName).ToString
Next
Next
ExcelWorkSheet.Columns.AutoFit()
ExcelWorkbook.SaveAs(FileName)
ExcelWorkbook.Close()
ExcelApp.Quit()
Catch ex As Exception
MsgBox("Err", MsgBoxStyle.Information + MsgBoxStyle.MsgBoxRtlReading)
Finally
ExcelApp = Nothing
ExcelWorkbook = Nothing
ExcelWorkSheet = Nothing
ColumnIndex = Nothing
RowIndex = Nothing
End Try
End Sub
if I have a code or telephone number that has a 0 as the first character, it does not show in excel file . I use this code to solve the problem:
ExcelWorkSheet.Activate()
ExcelWorkSheet.Cells().Columns.NumberFormat = "#"
ExcelWorkSheet.Cells().EntireColumn.NumberFormat = "#"
but it doesn't work. I read this question but cannot solve my problem:
Format an Excel column (or cell) as Text in C#?
Set data type like number, text and date in excel column using Microsoft.Office.Interop.Excel in c#
Insert DataTable into Excel Using Microsoft Access Database Engine via OleDb
Setting the format of a cell after you have data in it does not always work because some data may have been lost on entry in the conversion to the original data format. Make sure you set the format of the cell first so that any leading zeros do not get truncated.

Excel Date column returning INT using EPPlus

So i'm using EPPlus to read and write excel documents.
Workflow
User generates populated excel document
Opens document and adds a row
Uploaded and read
The dates that are generated when I create the document using EPPlus show correctly when I'm reading the value back but the row the user changes the date one or adds is showing as an INT value not something I can use as a real date.
When I enter the date 1/01/2014 and write it, the output when I open the file up shows 41640
I'm reading it as follows
sheet.Cells[i, "AE".ConvertExcelColumnIndex()].Value != null
? sheet.Cells[i, "AE".ConvertExcelColumnIndex()].Value.ToString().Trim()
: string.Empty
Update
When exporting the file I have added the following
DateTime testDate;
if (DateTime.TryParse(split[i], out testDate))
{
sheet.Cells[row, i + 1].Style.Numberformat.Format = "MM/dd/yyyy";
sheet.Cells[row, i + 1].Value = testDate.ToString("MM/dd/yyyy");
}
Also when reading the value back I have tried
sheet.Cells[i, "AE".ConvertExcelColumnIndex()].Style.Numberformat.Format = "MM/dd/yyy";
I still get an INT back
...when I need to read that excel file, the only dates that are
incorrect are the ones the user has changed
So when you read the modified excel-sheet, the modified dates are numbers whereas the unchanged values are strings in your date-format?
You could get the DateTime via DateTime.FromOADate:
long dateNum = long.Parse(worksheet.Cells[row, column].Value.ToString());
DateTime result = DateTime.FromOADate(dateNum);
With your sample-number:
Console.Write(DateTime.FromOADate(41640)); // -> 01/01/2014
I stumbled upon this issue today when trying to generate some Excel documents from some ASP.NET DataTables: I had no problem with strings, but ran into few issues with numeric types (int, doubles, decimals) and DataTables, which were formatted as string or as numeric representations (OADate).
Here's the solution I eventually managed to pull off:
if (dc.DataType == typeof(DateTime))
{
if (!r.IsNull(dc))
{
ws.SetValue(row, col, (DateTime)r[dc]);
// Change the following line if you need a different DateTime format
var dtFormat = "dd/MM/yyyy";
ws.Cells[row, col].Style.Numberformat.Format = dtFormat;
}
else ws.SetValue(row, col, null);
}
Apparently, the trick was to set the value as DateTime and then configure the proper Style.Numberformat.Formataccordingly.
I published the full code sample (DataTable to Excel file with EPPlus) in this post on my blog.
You should try using
string dateFromExcel = workSheet.Cells[row, col].Text.ToString();
DateTime localdt;
if (DateTime.TryParse(dateFromExcel, out localdt))
{
dateFromExcel = localdt.ToString("MM/dd/yyyy");
};
the Value reads the value in the general formatting while Text reads the value as it is from the excel with applied formatting.
you could check if the cell format is in date format,
then parse it to date
var cell = worksheet.Cells[row, col];
value = cell.Value.ToString();
if (cell.Style.Numberformat.Format == "[$-409]d\\-mmm\\-yy;#")
{
string inputString = DateTime.FromOADate(long.Parse(value.ToString())).ToString("dd-MMM-yyyy");
}
You can also change the 'NumberFormatLocal' property. This worked for me. If you format the Excel file before improting it using EPPLUS.
The following basic example of code formats column A in a typical excel file.
Sub ChangeExcelColumnFormat()
Dim ExcelApp As Excel.Application
Dim ExcelWB As Excel.Workbook
Dim ExcelWS As Excel.Worksheet
Dim formatRange As Excel.Range
Dim strFile As String = "C:\Test.xlsx"
Dim strSheetname As String = "Sheet1"
ExcelApp = New Excel.Application
ExcelWB = ExcelApp.Workbooks.Open(strFile)
strColSelect = "A:A"
strFormat = "dd/mm/yyyy"
formatRange = ExcelWS.Range(strColSelect)
formatRange.NumberFormatLocal = strFormat
ExcelWB.Save()
ExcelWB.Close()
ExcelApp.Quit()
ExcelWS = Nothing
ExcelWB = Nothing
ExcelApp = Nothing
End Sub

Convert number to text when exporting to excel

I am displaying my data(comma separated numbers) in a grid view, and it happens as needed. However, when I export it to excel, then the value is changed in terms of display
e.g my value is 901155465, 978785496, 987458986
Then it appears as 901,155,465,978,785,496,987,458,986
This is how I pass the data set into an excel. I know we can render the HTML also, but I needed to transfer the data only.
GridView GridView1 = new GridView();
GridView1.DataSource = myDataSet;
GridView1.DataBind();
string style = #" .text { mso-number-format:\#; } ";
Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=Report.xls");
Response.Charset = "";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
esponse.ContentType = "application/vnd.ms-excel";
System.IO.StringWriter s_Write = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter h_write = new HtmlTextWriter(s_Write);
GridView1.ShowHeader = true;
GridView1.RenderControl(h_write);
Response.Write(style);
Response.Write(s_Write.ToString());
Response.End();
It seems excel is treating the number as one number and adding comma at appropriate places.
Is there any solution to display data as shown in gridview.
Thanks in advance
try this:
_worksheet.Cells[1, 1] = "=\"" + YOUR_VALUE + "\"";
that's how I did using Interop.Excel
Excel will ignore the (=) since it starts a formula and the double quotes will tell excel to use that value as a String.
You could try to export the excel stylesheet also:
mso-number-format:"0" NO Decimals
http://cosicimiento.blogspot.fr/2008/11/styling-excel-cells-with-mso-number.html
Therefor you need to write it to the Response:
// ...
string style = #"<style> td { mso-number-format:"0"; } </style> ";
// Style is added dynamically
Response.Write(style);
Response.Write(s_Write.ToString());
// ...
try this it work fine
for (int i = 0; i < gvExportExcel.Rows.Count; i++)
gvExportExcel.Rows[i].Cells[0].Attributes.Add("style", "mso-number-format:\#");
This issue haunted me for like a year this helped me. I tried many solutions stackoverflow.com but it didn't help. Hope this helps someone
Dim formatRange As Excel.Range
formatRange = xlWorkSheet.Range("a1", "b1")
formatRange.NumberFormat = "#"
To put data in cell A1
xlWorkSheet.Cells(1, 1) = "098"
or if you are copying from a datagridview
xlWorkSheet.PasteSpecial("Text", False, False, Type.Missing, Type.Missing, Type.Missing, True)
http://vb.net-informations.com/excel-2007/vb.net_excel_page_format.htm
Good luck.
"\"\t" + value?.ToString() + "\"";
anyone can use this line of code, if you need to convert and export number or any value as it is.
For my case,
value = "13291440533000102";
When I was trying to export using StreamWriter, the value was exported correctly in CSV format. But during opening the .csv file, the excel was treating the value as number. And as the number is more than 16 characters, it was converted like 13291440533000100. Last char was changed. I have solved this by this was.

Using A Local file path in a Streamwriter object ASP.Net

I am trying to create a csv file of some data. I have wrote a function that successfully does this....
Private Sub CreateCSVFile(ByVal dt As DataTable, ByVal strFilePath As String)
Dim sw As New StreamWriter(strFilePath, False)
''# First we will write the headers.
''#DataTable dt = m_dsProducts.Tables[0];
Dim iColCount As Integer = dt.Columns.Count
For i As Integer = 0 To iColCount - 1
sw.Write(dt.Columns(i))
If i < iColCount - 1 Then
sw.Write(",")
End If
Next
sw.Write(sw.NewLine)
''# Now write all the rows.
For Each dr As DataRow In dt.Rows
For i As Integer = 0 To iColCount - 1
If Not Convert.IsDBNull(dr(i)) Then
sw.Write(dr(i).ToString())
End If
If i < iColCount - 1 Then
sw.Write(",")
End If
Next
sw.Write(sw.NewLine)
Next
sw.Close()
End Sub
The problem is I am not using the streamwriter object correctly for what I trying to accomplish. Since this is an asp.net I need the user to pick a local filepath to put the file on. If I pass any path to this function its gonna try to write it to the directory specified on the server where the code is. I would like this to popup and let the user select a place on their local machine to put the file....
Dim exData As Byte() = File.ReadAllBytes(Server.MapPath(eio))
File.Delete(Server.MapPath(eio))
Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", fn))
Response.ContentType = "application/x-msexcel"
Response.BinaryWrite(exData)
Response.Flush()
Response.End()
I am calling the first function in code like this...
Dim emplTable As DataTable = SiteAccess.DownloadEmployee_H()
CreateCSVFile(emplTable, "C:\\EmplTable.csv")
Where I dont want to have specify the file loaction (because this will put the file on the server and not on a client machine) but rather let the user select the location on their client machine.
Can someone help me put this together? Thanks in advance.
I have recreated my export function and now it lets the usr select a download path, but one column in the data being downloaded has data in the form of "Doe, John" this column is called "EPLNME" this messes up the output file because its reading the comma in the data and now the data is off by a column in the output file can someone help me stop this specific incident im not sure how I can. Here is the code...
Private Sub ExportCSV(ByVal data As DataTable, ByVal nameOfFile As String)
Dim context As HttpContext = HttpContext.Current
context.Response.Clear()
context.Response.ContentType = "text/csv"
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + nameOfFile + ".csv")
''#Write column header names
For i = 0 To data.Columns.Count - 1
If (i > 0) Then
context.Response.Write(",")
End If
context.Response.Write(data.Columns(i).ColumnName)
Next
context.Response.Write(Environment.NewLine)
''#Write data
For Each row As DataRow In data.Rows
For i = 0 To data.Columns.Count - 1
If (i > 0) Then
context.Response.Write(",")
End If
context.Response.Write(row.Item(i).ToString())
Next
context.Response.Write(Environment.NewLine)
Next
context.Response.End()
End Sub
First, you need to overload your function like this, to allow sending your output directly to either a stream or a path:
Private Sub CreateCSVFile(ByVal dt As DataTable, ByVal strFilePath As String)
Using sw As New StreamWriter(strFilePath)
CreateCSVFile(dt, sw)
End Using
End Sub
Private Sub CreateCSVFile(ByVal dt As DataTable, ByVal outStream As TextWriter)
''# First we will write the headers.
Dim delimiter As String = String.Empty
For Each col As DataColumn in dt.Columns
outStream.Write(delimiter)
outStream.Write(col.ColumnName)
delimiter = ","
Next col
outStream.Write(outStream.NewLine)
int flushCount = 0;
''# Now write all the rows.
For Each dr As DataRow In dt.Rows
delimiter = String.Empty
For i As Integer = 0 To dt.Columns.Count -1
outStream.Write(delimiter)
If Not Convert.IsDBNull(dr(i)) Then
outStream.Write("""") ''#Wrap fields in quotes to allow for commas in field data
''# Need to escape the quotes as well
outStream.Write(dr(i).ToString().Replace("""", """"""))
outStream.Write("""")
End If
delimiter = ","
Next i
outStream.Write(outStream.NewLine)
''# Flush the buffer periodically
flushCount += 1
If flushCount > 100 Then
outStream.Flush()
flushCount = 0
End If
Next dr
End Sub
Notice that your function works pretty much exactly the same as before, but you can now write to a file or directly to a stream, and you didn't have to re-write a lot of code to make it work. Pretty much anything you write that works with files should be written this way. I made a few other improvements to the code as well, but the main thing is the method that does the actual work should always accept a TextWriter and then just add overloads if you want to be able to accept anything else like a file path.
Now what you can do is take the Content Type and Header from Ben Robinson's answer and use this new method to write directly to the asp.net response buffer:
Response.ContentType = "text/csv";
Response.AddHeader("Content-Disposition", "attachment; filename=NameOfFile");
CreateCSVFile(SiteAccess.DownloadEmployee_H(), Response.Output)
Response.Flush()
Response.End()
You, don't really nead a streamwriter, that is for creating files on the machine where the code is running. Use a StringBuilder to build up the string that represents the CSV file then do the following:
Response.ContentType = "text/csv";
Response.AddHeader("Content-Disposition", "attachment; filename=NameOfFile");
Response.Write(MyStringBuilder.ToString());
If you do need to create a file because you need to store it on the server and also transmit it to the user. Create the file as you are doing and the replace the last line with
Response.TransmitFile("filePath");
You can use a MemoryStream to hold the binary data on the server, instead of writing them to a file.
1) Write the contents youn want to put in the CSV into the memory stream
2) Read from the MemoryStream into the Response when required.
Hope it helps!

Categories