I have a server that can't have any office installed on it, so I'm using ClosedXML to do some manipulations on excel files.
But ClosedXML only works on .xlsx file and I also have xls file to handle.
I spend almost a full day searching for a way to convert .xls files to .xlsx files without using any office libraries (since there is no office installed on my designated server...)
Can someone PLEASE tell me how can I convert these .xls files to .xlsx files ?
I can't use Microsoft.Office.Interop because it requires having office installed on the server.
For Microsoft.Office.Interop you need to have office installed.
You could use OleDb to read it(f.e. into a DataTable). Then use a library like EPPlus or OpenXml to write the xlsx file. Both don't need to have office installed.
Creating an xlsx file from a DataTable with EPPLus is easy:
using (ExcelPackage pck = new ExcelPackage(newFile))
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Name of Worksheet");
ws.Cells["A1"].LoadFromDataTable(dataTable, true);
pck.Save();
}
The first link above shows how to get a DataTable from an xls-file.
Thanks to #Tim Schmelter.
Here is the code I got from the links:
private static string GetConnectionString()
{
Dictionary<string, string> props = new Dictionary<string, string>();
// XLSX - Excel 2007, 2010, 2012, 2013
props["Provider"] = "Microsoft.ACE.OLEDB.12.0;";
props["Extended Properties"] = "Excel 12.0 XML";
props["Data Source"] = #"D:\data\users\liran-fr\Desktop\Excel\Received\Orbotech_FW__ARTEMIS-CONTROL-AG__223227__0408141043__95546.xls";
// XLS - Excel 2003 and Older
//props["Provider"] = "Microsoft.Jet.OLEDB.4.0";
//props["Extended Properties"] = "Excel 8.0";
//props["Data Source"] = "C:\\MyExcel.xls";
StringBuilder sb = new StringBuilder();
foreach (KeyValuePair<string, string> prop in props)
{
sb.Append(prop.Key);
sb.Append('=');
sb.Append(prop.Value);
sb.Append(';');
}
return sb.ToString();
}
private static DataSet ReadExcelFile()
{
DataSet ds = new DataSet();
string connectionString = GetConnectionString();
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
// Get all Sheets in Excel File
DataTable dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
// Loop through all Sheets to get data
foreach (DataRow dr in dtSheet.Rows)
{
string sheetName = dr["TABLE_NAME"].ToString();
//if (!sheetName.EndsWith("$"))
// continue;
// Get all rows from the Sheet
cmd.CommandText = "SELECT * FROM [" + sheetName + "]";
DataTable dt = new DataTable();
dt.TableName = sheetName;
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dt);
ds.Tables.Add(dt);
}
cmd = null;
conn.Close();
}
return ds;
}
using (ExcelPackage epackage = new ExcelPackage())
{
ExcelWorksheet excel = epackage.Workbook.Worksheets.Add("ExcelTabName");
DataSet ds = ReadExcelFile();
DataTable dtbl = ds.Tables[0];
excel.Cells["A1"].LoadFromDataTable(dtbl, true);
System.IO.FileInfo file = new System.IO.FileInfo(#"D:\data\users\liran-fr\Desktop\Excel\Received\test.xlsx");
epackage.SaveAs(file);
}
Related
I need to read a single cell from an xsl excel file to a string withing the web application i am building. I was previously pulling cell ranges from the file to a table using the following code:
string PullFromExcell(string CellNo)
{
string cell;
string properties = String.Format(#"Provider = Microsoft.Jet.OLEDB.4.0; Data Source = C:\Users\User\Desktop\file.xls; Extended Properties = 'Excel 8.0;'");
using (OleDbConnection conn = new OleDbConnection(properties))
{
string worksheet = "Sheet";
conn.Open();
DataSet ds = new DataSet();
using (OleDbDataAdapter da = new OleDbDataAdapter("SELECT * FROM [" + worksheet + "$" + CellNo + "]", properties))
{
DataTable dt = new DataTable();
cell = dt.ToString();
da.Fill(dt);
ds.Tables.Add(dt);
grdComponent.DataSource = dt;
grdComponent.DataBind();
}
}
return cell;
}
How would i send that to a string? The code that i would use when pulling from a database is similar to this:
Sqlstring = "Select data from variable where name = 'fred' and ssn = 1234";
var cmd0 = new SqlCommand(Sqlstring, Class_Connection.cnn);
string Data = cmd0.ExecuteScalar().ToString();
i'm just not sure if any of that is compatible.
After filling DataTable, you can search the row like this:
foreach (DataRow dr in dt.Rows)
{
if (dr["name"] == "fred" && dr["ssn"] == "1234")
{
cell = dr["data"].ToString();
break;
}
}
I need to open view and Edit an Excel File within a Windows form.
I tried implementing the code for opening the Excel file in Gridview and then edit it, but that becomes too much lengthy process, hence I need to find a convenient way of View and Edit an Excel File in WindowsForms.
Any help would be appreciated.
Thanks,
You might want to use OLEDB to read and query excel the below method returns a specific sheet in an excel file as a data table, which later you can set as Data source to your gridview.
public static DataTable ConvertExcelToDataTableGroupSubGroup(string FileName)
{
DataTable dtResult = null;
int totalSheet = 0; //No of sheets on excel file
using (OleDbConnection objConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + FileName + ";Extended Properties='Excel 12.0;HDR=YES;IMEX=1;';"))
{
objConn.Open();
OleDbCommand cmd = new OleDbCommand();
OleDbDataAdapter oleda = new OleDbDataAdapter();
DataSet ds = new DataSet();
DataTable dt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string sheetName = string.Empty;
if (dt != null)
{
var tempDataTable = (from dataRow in dt.AsEnumerable()
where !dataRow["TABLE_NAME"].ToString().Contains("FilterDatabase")
select dataRow).CopyToDataTable();
dt = tempDataTable;
totalSheet = dt.Rows.Count;
// Sheet from first index
sheetName = dt.Rows[1]["TABLE_NAME"].ToString();
}
cmd.Connection = objConn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM [" + sheetName + "]";
oleda = new OleDbDataAdapter(cmd);
oleda.Fill(ds, "excelData");
dtResult = ds.Tables["excelData"];
objConn.Close();
return dtResult; //Returning Dattable
}
}
OLEDB also gives you the flexibility to write SQL queries on excel.
First, you need to install 2 Library in NuGet
ExcelDataReader
ExcelDataReader.DataSet
https://github.com/ExcelDataReader/ExcelDataReader
It can be possible read and write *.XLS, *.XLSX without Office or OLE Connection.
And this is source what I'm using :)
using ExcelDataReader;
private DataSet ds;
IExcelDataReader reader = null;
OpenFileDialog openFileDialog = new OpenFileDialog();
private void btnOpen_Click(object sender, EventArgs e)
{
openFileDialog.Filter = "Excel files (*.xls;*.xlsx)|*.xls;*.xlsx";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
tbPath.Text = openFileDialog.FileName;
var file = new FileInfo(tbPath.Text);
try
{
using (var stream = new FileStream(tbPath.Text, FileMode.Open))
{
if (reader != null) { reader = null; }
// Judge it is .xls or .xlsx
if (file.Extension == ".xls") { reader = ExcelReaderFactory.CreateBinaryReader(stream); }
else if (file.Extension == ".xlsx") { reader = ExcelReaderFactory.CreateOpenXmlReader(stream); }
if (reader == null) { return; }
ds = reader.AsDataSet(new ExcelDataSetConfiguration()
{
UseColumnDataType = true,
ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
{
UseHeaderRow = false,
ReadHeaderRow = (rowReader) => {
rowReader.Read();
},
// Gets or sets a callback to determine whether to include the
// current row in the DataTable.
FilterRow = (rowReader) => {
return true;
},
}
});
var tablenames = GetTablenames(ds.Tables);
cbSheet.DataSource = tablenames;
listSheet.DataSource = tablenames;
if (cbSheet.Items.Count == 1)
{
cbSheet.SelectedIndex = 0;
}
}
cbSheet.Enabled = true;
btnOpen.Enabled = true;
}
catch (Exception ex)
{
tbPath.Text = "";
cbSheet.Enabled = false;
btnOpen.Enabled = true;
MessageBox.Show(ex.Message);
}
}
}
I am trying to find a faster way to read an XML file that can be opened in Excel 2010. I cannot immediately read the XML file using readxml method because it contains Workbook, style, cell, data and other tags. So my approach was to open it in Excel then get the data on sheet 2 only. The sample file contains 9,000+ rows and takes about 2mins 49secs to store in a datatable. The actual file has 25,000+ rows. This is what I have tried:
private void bulkInsert()
{
var s = new Stopwatch();
s.Start();
try
{
KillExcel();
GCollector();
Excel.Application app = null;
app = new Excel.Application();
Excel.Worksheet sheet = null;
Excel.Workbook book = null;
book = app.Workbooks.Open(#"my directory for the file");
sheet = (Worksheet)book.Sheets[2];
sheet.Select(Type.Missing);
var xlRange = (Excel.Range)sheet.Cells[sheet.Rows.Count, 1];
int lastRow = (int)xlRange.get_End(Excel.XlDirection.xlUp).Row;
int newRow = lastRow + 1;
var cellrow = newRow;
int columns = sheet.UsedRange.Columns.Count;
Excel.Range test = sheet.UsedRange;
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("Node_SegmentName");
dt.Columns.Add("Type");
dt.Columns.Add("Sub-Type");
dt.Columns.Add("Description");
dt.Columns.Add("Parameter_DataIdentifier");
dt.Columns.Add("RuntimeValue");
dt.Columns.Add("Category");
dt.Columns.Add("Result");
dt.TableName = "SsmXmlTable";
//slow part
for (i = 0; i < lastRow; i++)
{
DataRow excelRow = dt.NewRow();
for (int j = 0; j < columns; j++)
{
excelRow[j] = test.Cells[i + 2, j + 1].Value2;
}
dt.Rows.Add(excelRow);
}
dataGridView1.DataSource = dt;
DataSet ds = new DataSet();
ds.Tables.Add(dt);
ds.WriteXml(AppDomain.CurrentDomain.BaseDirectory + String.Format("\\XMLParserOutput{0}.xml", DateTime.Now.ToString("MM-d-yyyy")));
DataSet reportData = new DataSet();
reportData.ReadXml(AppDomain.CurrentDomain.BaseDirectory + String.Format("\\XMLParserOutput{0}.xml", DateTime.Now.ToString("MM-d-yyyy")));
SqlConnection connection = new SqlConnection("Data Source=YOURCOMPUTERNAME\\SQLEXPRESS;Initial Catalog=YOURDATABASE;Integrated Security=True;Connect Timeout=0");
connection.Open();
SqlBulkCopy sbc = new SqlBulkCopy(connection);
sbc.DestinationTableName = "Test";
sbc.WriteToServer(reportData.Tables["SsmXmlTable"]);
connection.Close();
s.Stop();
var duration = s.Elapsed;
MessageBox.Show(duration.ToString() + " bulk insert way");
MessageBox.Show(ds.Tables["SsmXmlTable"].Rows.Count.ToString());//439 rows
}
catch (Exception ex)
{
KillExcel();
GCollector();
MessageBox.Show(ex.ToString() + i.ToString());
}
}
Without the reading from Excel part, the insertion of data using bulk copy only takes a couple of seconds (0.5secs for 449 rows).
For others who are encountering the same issue, what I did was:
save the xml as an xlsx file
use oledb to read the xlsx file
store in dataset using OleDbAdapter (Fill() method)
bulk insert
Here is the code that I used to do this (change the connection string):
Stopwatch s = new Stopwatch();
s.Start();
string sSheetName = null;
string sConnection = null;
System.Data.DataTable sheetData = new System.Data.DataTable();
System.Data.DataTable dtTablesList = default(System.Data.DataTable);
OleDbConnection oleExcelConnection = default(OleDbConnection);
sConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + #"C:\Users\YOURUSERNAME\Documents\Visual Studio 2012\Projects\TestXmlParser\TestXmlParser\bin\Debug\ConsolidatedSSMFiles.xlsx" + ";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\"";
oleExcelConnection = new OleDbConnection(sConnection);
oleExcelConnection.Open();
dtTablesList = oleExcelConnection.GetSchema("Tables");
if (dtTablesList.Rows.Count > 0)
{
sSheetName = dtTablesList.Rows[0]["TABLE_NAME"].ToString();
}
dtTablesList.Clear();
dtTablesList.Dispose();
if (!string.IsNullOrEmpty(sSheetName))
{
OleDbDataAdapter sheetAdapter = new OleDbDataAdapter("select * from [TEST$]", oleExcelConnection);
sheetAdapter.Fill(sheetData);
} s.Stop();
var duration = s.Elapsed;
oleExcelConnection.Close();
dataGridView1.DataSource = sheetData;
MessageBox.Show(sheetData.Rows.Count.ToString()+"rows - "+ duration.ToString());
This reads 25000+ rows of excel data to a datable in approx. 1.9 to 2.0 seconds.
I have created a excel sheet with the help of creating simple excel sheet in c# with strings as input link. It works fine the error when we open the saved excel sheet it shows message box like "excel found unreadable content in "sample.xls". Do you want to recover the contents of this workbook? If you trust the source of this workbook, Click Yes". May I know How it shows like this? My sample code is
protected void Button1_Click(object sender, EventArgs e)
{
//Create the data set and table
DataSet ds = new DataSet("New_DataSet");
DataTable dt = new DataTable("New_DataTable");
//Set the locale for each
ds.Locale = System.Threading.Thread.CurrentThread.CurrentCulture;
dt.Locale = System.Threading.Thread.CurrentThread.CurrentCulture;
//Create a query and fill the data table with the data from the DB
SqlConnection conn= new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString);
SqlCommand cmd =new SqlCommand ("SELECT Name,EmpCode FROM EmpDetails where EmpCode='"+Neena102+"'",conn);
// dr = conn.query(str);
SqlDataAdapter adr = new SqlDataAdapter();
adr.SelectCommand = cmd;
adr.Fill(dt);
//Add the table to the data set
ds.Tables.Add(dt);
var rows = ds.Tables[0].Rows;
foreach (DataRow row in rows)
{
string name=Convert.ToString(row["Name"]);
//Here's the easy part. Create the Excel worksheet from the data set
ExcelLibrary.DataSetHelper.CreateWorkbook(#"F:\\reports\\"+name+".xls", ds);
System.Diagnostics.Process.Start(#"F:\\reports\\" + name + ".xls");
}
}
Please try the following changes.
Process startExcel = System.Diagnostics.Process.Start(#"F:\reports\" + name + ".xls");
startExcel.WaitForExit();
Hi I am importing a excel or a .csv file using OpenFileDialog in Visual Studio 2005.
I need to show all the headers in a list, which is supposed to be listed on a ComboBox.
e.g If I import a file which has 10 columns in it, my drop down should show me 10 values as
1, 2, 3..........10
Please let me know how to go about it.
CSV is completely different animal than Excel.
I would use the OpenXml library OR use the OleDb driver to read from the excel file.
Look here: Reading excel file using OLEDB Data Provider
You will need to have the ACE driver installed, you may already have it though.
// first read *.xls file into a DataTable; don't wory it is very quick.
public DataTable ReadExcelFile(string strFilePath)
{
string sConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" + strFilePath + "; Extended Properties=\"Excel 8.0; HDR=No; IMEX=1;\"";
OleDbConnection objConn = new OleDbConnection(sConnectionString);
objConn.Open();
DataTable sdt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
// Change this part to read 1 row
String str = "SELECT TOP(2) * FROM [" + sdt.Rows[0]["TABLE_NAME"].ToString() + "]";
//String str = "SELECT * FROM [" + sdt.Rows[0]["TABLE_NAME"].ToString() + "]";
OleDbCommand objCmdSelect = new OleDbCommand(str, objConn);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
DataTable dt = new DataTable();
objAdapter1.Fill(dt);
objConn.Close();
dt.AcceptChanges();
return dt;
}
Now working with DataTable
DataTable dt = ReadExcelFile(#"c:\\x.xlsx");
if (dt != null)
{
System.Windows.Forms.ComboBox cmb = new System.Windows.Forms.ComboBox();
for (int i = 0; i < dt.Columns.Count; i++)
cmb.Items.Insert(i, dt.Columns[i].ColumnName);
}