My VB.NET app currently allows me to convert CSV files to a datatable thanks to the code provided by David in this question I posted: Previous Question
Now I am trying to allow .XLSX files to be imported to a datatable as well. Currently the code looks like this:
Private Function ConvertCSVToDataTable(ByVal path As String) As DataTable
Dim dt As DataTable = New DataTable()
Using con As OleDb.OleDbConnection = New OleDb.OleDbConnection()
Try
If System.IO.Path.GetExtension(path) = ".csv" Then
con.ConnectionString = String.Format("Provider={0};Data Source={1};Extended Properties=""Text;HDR=YES;FMT=Delimited""", "Microsoft.Jet.OLEDB.4.0", IO.Path.GetDirectoryName(path))
ElseIf System.IO.Path.GetExtension(path) = ".xlsx" Then
con.ConnectionString = String.Format("Provider={0};Data Source={1};Extended Properties=""Excel 12.0 XML;HDR=Yes;""", "Microsoft.ACE.OLEDB.12.0", IO.Path.GetDirectoryName(path))
End If
Using cmd As OleDb.OleDbCommand = New OleDb.OleDbCommand("SELECT * FROM " & IO.Path.GetFileName(path), con)
Using da As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter(cmd)
con.Open()
da.Fill(dt)
con.Close()
End Using
End Using
Catch ex As Exception
Console.WriteLine(ex.ToString())
Finally
If con IsNot Nothing AndAlso con.State = ConnectionState.Open Then
con.Close()
End If
End Try
End Using
Return dt
End Function
However, when I run the code using the .XLSX file, I get the following error:
{"The Microsoft Office Access database engine cannot open or write to
the file 'C:\Users\XSLXFilePath'. It is already opened exclusively by
another user, or you need permission to view and write its data."}
The file is not open anywhere else to my knowledge. And the app also runs fine when .CSV file is put through it instead. How do I get the app to properly work for .XLSX, or any Excel file format?
I think that the error is that from the connection string and the OLEDB Command:
ConnectionString
You don't have to use IO.Path.GetDirectoryName(path) it returns the directory name, you have to provide the file full path:
con.ConnectionString = String.Format("Provider={0};Data Source={1};Extended Properties=""Excel 12.0 XML;HDR=Yes;""", "Microsoft.ACE.OLEDB.12.0", path)
Refer to this link for excel connectionstring generation function: import data from excel 2003 to dataTable
OLEDB Command
You must provide the Worksheet name in the Command instead of the Filename:
Using cmd As OleDb.OleDbCommand = New OleDb.OleDbCommand("SELECT * FROM [Sheet1$]" , con)
If the Sheet names is dynamic and you have to get the first sheet in the excel file:
Dim dbSchema as DataTable = con.GetOleDbSchemaTable (OleDbSchemaGuid.Tables, null)
Dim firstSheetname as String = dbSchema.Rows(0)("TABLE_NAME").ToString
Using cmd As OleDb.OleDbCommand = New OleDb.OleDbCommand("SELECT * FROM [" & firstSheetname & "]" , con)
References
Reading from excel using oledbcommand
Read and Write Excel Documents Using OLEDB
Use can use the following connection string for .xlsx file.
I have used it and working fine.
P_FIle = ( File Name with path )
P_Con_Str = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & P_File & ";Extended Properties=""Excel 12.0 XML;HDR=Yes;"""
Related
I am developing a website on VisualStudio using VB. In one section of my site I make a DataBase Query, store the result in a DataTable and display it. I give the user the option of dowloading the information, what I would like to do is to download an XLS file to the client's side with the information in the datatable without creating the xls on the server side.
I currently have the following code section to send the file to the user
Dim fileToDownload = Server.MapPath("~/docs/QuejometroVF.pdf")
Response.ContentType = "application/octet-stream"
Dim cd = New ContentDisposition()
cd.Inline = False
cd.FileName = Path.GetFileName(fileToDownload)
Response.AppendHeader("Content-Disposition", cd.ToString())
Dim fileData = System.IO.File.ReadAllBytes(fileToDownload)
Response.OutputStream.Write(fileData, 0, fileData.Length)
But it requires a path to a local file in order to send it.
First I would like to know how to create a xls file from the datatable (only in memory) and then send that object as a file to the client's computer. If it is not possible, Could you tell me how to write the xls file in my server so I can then send it using the code above? I have not really figured out how to do it yet.
I was thinking on doint it that way because I don't want to keep files in the server when I already have that information on the database and I don't pretend on keeping that file stored.
Thank you
I export data to xls file using the following code, my backend is an Oracle database and that's where I get the data:
Dim MyConnection As OracleConnection = OpenConnection(Session("USERNAME"), Session("PASSWORD"))
Dim MyDataSet As New DataSet
MyDataSet = GetExportData(MyConnection, Session("UserDataKey"), Session("CompoundKey"), Session("LastOfCompoundKey"))
'I rename the dataset's table columns to what I want in the xls file
MyDataSet.Tables!data.Columns(0).ColumnName = "IDNumber"
MyDataSet.Tables!data.Columns(1).ColumnName = "FirstName"
MyDataSet.Tables!data.Columns(2).ColumnName = "LastName"
MyDataSet.Tables!data.Columns(3).ColumnName = "Address"
MyDataSet.Tables!data.Columns(4).ColumnName = "City"
MyDataSet.Tables!data.Columns(5).ColumnName = "State"
MyDataSet.Tables!data.Columns(6).ColumnName = "ZipCode"
MyDataSet.Tables!data.Columns(7).ColumnName = "Phone_Area"
MyDataSet.Tables!data.Columns(8).ColumnName = "Phone_Prefix"
MyDataSet.Tables!data.Columns(9).ColumnName = "Phone_Suffix"
MyDataSet.Tables!data.Columns(10).ColumnName = "Email"
MyDataSet.Tables!data.Columns(11).ColumnName = "BirthDay"
Response.ClearContent()
'I create the filename I want the data to be saved to and set up the response
Response.AddHeader("content-disposition", "attachment; filename=" & Replace(Session("Key0"), " ", "-") & "-" & Session("Key1") & "-" & Replace(Replace(Trim(Session("Key2")), ".", ""), " ", "-") & ".xls")
Response.ContentType = "application/excel"
Response.Charset = ""
EnableViewState = False
Dim tw As New System.IO.StringWriter
Dim hw As New System.Web.UI.HtmlTextWriter(tw)
'Create and bind table to a datagrid
Dim dgTableForExport As New DataGrid
If MyDataSet.Tables.Count > 0 Then
If MyDataSet.Tables(0).Rows.Count > 0 Then
dgTableForExport.DataSource = MyDataSet.Tables(0) ' .DefaultView
dgTableForExport.DataBind()
'Finish building response
Dim strStyle As String = "<style>.text { mso-number-format:\#; } </style>"
For intTemp As Integer = 0 To MyDataSet.Tables(0).Rows.Count - 1
For intTemp2 As Integer = 0 To MyDataSet.Tables(0).Columns.Count - 1
dgTableForExport.Items(intTemp).Cells(intTemp2).Attributes.Add("class", "text")
Next
Next
End If
End If
dgTableForExport.RenderControl(hw)
Response.Write(style)
' Write the HTML back to the browser.
Response.Write(tw.ToString())
Response.End()
'Close, clear and dispose
MyConnection.Close()
MyConnection.Dispose()
MyConnection = Nothing
I copied and pasted this from one of my projects, it's untested and may contain error but should get you started.
You can use a MemoryStream or to write the file to Response stream using Response.Write method.
Creating an excel file from a data table is fairly easy as you can just create a GridView and bind the table to it.
Here is a code snippet that does what you need.
Public Sub DownloadExcel(outputTable as System.Data.DataTable)
Dim gv As New GridView
Dim tw As New StringWriter
Dim hw As New HtmlTextWriter(tw)
Dim sheetName As String = "OutputFilenameHere"
gv.DataSource = outputTable
gv.DataBind()
gv.RenderControl(hw)
Response.AddHeader("content-disposition", "attachment; filename=" & sheetName & ".xls")
Response.ContentType = "application/octet-stream"
Response.Charset = ""
EnableViewState = False
Response.Write(tw.ToString)
Response.End()
End Sub
There are a few issues with this method:
This doesn't output a native excel file. Instead, it outputs the HTML for a GridView that Excel will detect and notify the user that the content doesn't match the extension. However, it WILL display in Excel correctly if the user selects 'Yes' from the dialog box.
Earlier versions of Firefox and Chrome didn't like this method and instead download the file with a .html extension. I just tested it in both browsers and it worked with the most up to date versions.
Ideally, you should probably use Excel on your webserver to create native spreadsheets, but this will work if you (like me) don't have the means to do so.
I'm using an OleDbConnection to create an Excel file:
String bewegungenDateiname = System.IO.Path.ChangeExtension(System.IO.Path.GetTempFileName(), ".xls");
string strConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
+ System.IO.Path.GetDirectoryName(bewegungenDateiname) + #"\" + System.IO.Path.GetFileName(bewegungenDateiname)
+ #";Extended Properties='Excel 8.0;HDR=YES'";
using (System.Data.OleDb.OleDbConnection objConn = new System.Data.OleDb.OleDbConnection(strConnectionString))
using (System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand("", objConn))
{
objConn.Open();
cmd.CommandText = "CREATE TABLE [Test] ([MyDecimal] DECIMAL NULL)";
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
Decimal value = 12.34m;
cmd.Parameters.AddWithValue("#P01", value);
cmd.CommandText = "INSERT INTO [Test$] ([MyDecimal]) VALUES (#P01)";
cmd.ExecuteNonQuery();
}
System.Diagnostics.Process.Start(bewegungenDateiname);
Now when Excel 2013 opens the Excel file it will Show:
MyDecimal
1234
So in my case Excel is losing the dot. Now I'm running a german Version of Windows/Office and if I use the following line to add the Parameter it will work:
cmd.Parameters.AddWithValue("#P01", value.ToString());
German localization of numbers uses a colon instead of the dot to separate the fractions from the number value (meaning 12,34 instead of 12.34). So it seems the OleDbConnection uses the wrong culture variant to write the Excel file?
I fear my Version might break with a different Version of Excel or a different locale - is there a way to fix this and get decimal values to Excel without such risks?
I would use some other way to create Excel files, if it is without this flaw.
With Excel 2013 try using the following:
strConnectionString = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=""Excel 12.0;HDR=No;IMEX=1""", _filePath)
I have no idea if it will solve the problem.
Thanks Astander for replying to my query
I am here with more detailed query.
string cs = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + #"D:\\sample.xls;" + "Excel 12.0;HDR=YES;";
OleDbConnection Excelcon = new OleDbConnection(cs);
OleDbDataAdapter ad = new OleDbDataAdapter();
ad.SelectCommand = new OleDbCommand("SELECT *FROM [Sheet1$]", Excelcon);
DataTable dt = new DataTable();
ad.Fill(dt);
return dt;
I am getting error at the select statement that :
The Microsoft Office Access database engine could not find the object 'Sheet1$'. Make sure the object exists and that you spell its name and the path name correctly.
Hope someone can help me find a solution.
What worked for me is,
when file was created, it was stored in some specific location. In my case,C:/Documents.
I had manually changed the location to D:
this was what I had written
string connStringExcel = #"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=D:\example.xls;Extended Properties=""Excel 12.0;HDR=YES;""";`
So,the actual path should be
string connStringExcel = #"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=C:\A\Documents\example.xls;Extended Properties=""Excel 12.0;HDR=YES;""";`
So on giving the path of correct location,my query was solved.
Hope it helps someone else too.
// Create connection string variable. Modify the "Data Source"
// parameter as appropriate for your environment.
String sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=" + Server.MapPath("../ExcelData.xls") + ";" +
"Extended Properties=Excel 8.0;";
// Create connection object by using the preceding connection string.
OleDbConnection objConn = new OleDbConnection(sConnectionString);
// Open connection with the database.
objConn.Open();
// The code to follow uses a SQL SELECT command to display the data from the worksheet.
// Create new OleDbCommand to return data from worksheet.
OleDbCommand objCmdSelect =new OleDbCommand("SELECT * FROM myRange1", objConn);
// Create new OleDbDataAdapter that is used to build a DataSet
// based on the preceding SQL SELECT statement.
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
// Pass the Select command to the adapter.
objAdapter1.SelectCommand = objCmdSelect;
// Create new DataSet to hold information from the worksheet.
DataSet objDataset1 = new DataSet();
// Fill the DataSet with the information from the worksheet.
objAdapter1.Fill(objDataset1, "XLData");
// Bind data to DataGrid control.
DataGrid1.DataSource = objDataset1.Tables[0].DefaultView;
DataGrid1.DataBind();
// Clean up objects.
objConn.Close();
ref to thisLink
I am writing an application which uses an OleDbAdapter to access information in an Excel file. When I try to create a connection to the Excel file if the user has another (unrelated) Excel file open on their desktop then the file being connected to by the adapter opens in this window in Read-Only format. If the user does not have an instance of Excel open then the files stay hidden.
Here is my code:
foreach (item app in apps)
{
DataTable dt = new DataTable();
string CnStr = ("Provider=Microsoft.Jet.OLEDB.4.0;" + ("Data Source="
+ ((app.FilePath) + (";" + "Extended Properties=\"Excel 8.0;\""))));
string OleDbString = ("Select * from [" + app.SheetName + "$]");
OleDbDataAdapter Adapter = new OleDbDataAdapter();
var conn = new OleDbConnection(CnStr);
conn.Open(); <----------------------------This is where the files are being opened.
var cmd = new OleDbCommand(OleDbString, conn);
Adapter.SelectCommand = cmd;
Adapter.Fill(app.DataTable);
conn.Close();
Adapter.Dispose();
}
Does anybody know why the OleDbConnection() would open a file if an instance of Excel was open but would not if one was not?
You should post the code to initialize your apps variable. Most probably the answer to your question lies in there.
Does it use a GetObject or CreateObject method?
This is my first attempt to read an Excel 2007 file via ADO.net, and I must be missing something b/c when I try to run the query, I get an exception. When I started looking, it's b/c the table (worksheet) isn't there. Can someone please tell me what I'm doing wrong?
Here is my code:
string cs = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=My File.xlsx;Extended Properties=""Excel 12.0;IMEX=1;""";
using (OleDbConnection con = new OleDbConnection(cs))
{
con.Open();
string query = "SELECT * FROM [Sheet1$]";
OleDbCommand cmd = new OleDbCommand(query, con);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
DataTable dt = new DataTable();
DataTable worksheets = con.GetSchema("Tables");
adapter.Fill(dt);
.
.
.
}
Take a look at the accepted answer here
The First Column of the excel file to put in string variable C#?
It works for Excel 2003 but I think it could easily be adapted to work with 2007.