如何读取C#中的Excel文件,而不会丢失任何列?
我已经使用OleDb连接成功读取excel文件已经有一段时间了,但是我遇到了一个问题。 我有一个人试图在第一列中没有任何内容的情况下上传Excel电子表格,当我尝试读取文件时,它不能识别该列。
我目前使用下面的OleDb连接string:
提供商= Microsoft.Jet.OLEDB.4.0;
数据源= c:\ test.xls;
Extended Properties =“Excel 8.0; IMEX = 1;”
所以,如果excel文件中有13列,我回来的OleDbDataReader只有12列/字段。
任何有识之士将不胜感激。
SpreadsheetGear for .NET为您提供了一个用于处理来自.NET的xls和xlsx工作簿的API。 它比OleDB或Excel COM对象模型更容易使用并且更快速。 你可以看到现场的样品或免费试用 。
免责声明:我自己的SpreadsheetGear LLC
编辑:
StingyJack评论说:“ 比OleDb更快?更好的声称 ”。
这是一个合理的要求。 我总是看到我所知道的一个事实是错误的,所以我不能责怪任何人持怀疑态度。
下面是用SpreadsheetGear创build一个50,000行10列工作簿的代码,将其保存到磁盘,然后使用OleDb和SpreadsheetGear对数字进行求和。 SpreadsheetGear在0.31秒内读取500K单元格,而OleDB则为0.63秒 – 仅仅快了一倍。 SpreadsheetGear实际上创build并读取工作簿的时间比使用OleDB读取工作簿的时间要less。
代码如下。 您可以使用SpreadsheetGear免费试用版自行试用。
using System; using System.Data; using System.Data.OleDb; using SpreadsheetGear; using SpreadsheetGear.Advanced.Cells; using System.Diagnostics; namespace SpreadsheetGearAndOleDBBenchmark { class Program { static void Main(string[] args) { // Warm up (get the code JITed). BM(10, 10); // Do it for real. BM(50000, 10); } static void BM(int rows, int cols) { // Compare the performance of OleDB to SpreadsheetGear for reading // workbooks. We sum numbers just to have something to do. // // Run on Windows Vista 32 bit, Visual Studio 2008, Release Build, // Run Without Debugger: // Create time: 0.25 seconds // OleDb Time: 0.63 seconds // SpreadsheetGear Time: 0.31 seconds // // SpreadsheetGear is more than twice as fast at reading. Furthermore, // SpreadsheetGear can create the file and read it faster than OleDB // can just read it. string filename = @"C:\tmp\SpreadsheetGearOleDbBenchmark.xls"; Console.WriteLine("\nCreating {0} rows x {1} columns", rows, cols); Stopwatch timer = Stopwatch.StartNew(); double createSum = CreateWorkbook(filename, rows, cols); double createTime = timer.Elapsed.TotalSeconds; Console.WriteLine("Create sum of {0} took {1} seconds.", createSum, createTime); timer = Stopwatch.StartNew(); double oleDbSum = ReadWithOleDB(filename); double oleDbTime = timer.Elapsed.TotalSeconds; Console.WriteLine("OleDb sum of {0} took {1} seconds.", oleDbSum, oleDbTime); timer = Stopwatch.StartNew(); double spreadsheetGearSum = ReadWithSpreadsheetGear(filename); double spreadsheetGearTime = timer.Elapsed.TotalSeconds; Console.WriteLine("SpreadsheetGear sum of {0} took {1} seconds.", spreadsheetGearSum, spreadsheetGearTime); } static double CreateWorkbook(string filename, int rows, int cols) { IWorkbook workbook = Factory.GetWorkbook(); IWorksheet worksheet = workbook.Worksheets[0]; IValues values = (IValues)worksheet; double sum = 0.0; Random rand = new Random(); // Put labels in the first row. foreach (IRange cell in worksheet.Cells[0, 0, 0, cols - 1]) cell.Value = "Cell-" + cell.Address; // Using IRange and foreach be less code, // but we'll do it the fast way. for (int row = 1; row <= rows; row++) { for (int col = 0; col < cols; col++) { double number = rand.NextDouble(); sum += number; values.SetNumber(row, col, number); } } workbook.SaveAs(filename, FileFormat.Excel8); return sum; } static double ReadWithSpreadsheetGear(string filename) { IWorkbook workbook = Factory.GetWorkbook(filename); IWorksheet worksheet = workbook.Worksheets[0]; IValues values = (IValues)worksheet; IRange usedRahge = worksheet.UsedRange; int rowCount = usedRahge.RowCount; int colCount = usedRahge.ColumnCount; double sum = 0.0; // We could use foreach (IRange cell in usedRange) for cleaner // code, but this is faster. for (int row = 1; row <= rowCount; row++) { for (int col = 0; col < colCount; col++) { IValue value = values[row, col]; if (value != null && value.Type == SpreadsheetGear.Advanced.Cells.ValueType.Number) sum += value.Number; } } return sum; } static double ReadWithOleDB(string filename) { String connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + filename + ";" + "Extended Properties=Excel 8.0;"; OleDbConnection connection = new OleDbConnection(connectionString); connection.Open(); OleDbCommand selectCommand =new OleDbCommand("SELECT * FROM [Sheet1$]", connection); OleDbDataAdapter dataAdapter = new OleDbDataAdapter(); dataAdapter.SelectCommand = selectCommand; DataSet dataSet = new DataSet(); dataAdapter.Fill(dataSet); connection.Close(); double sum = 0.0; // We'll make some assumptions for brevity of the code. DataTable dataTable = dataSet.Tables[0]; int cols = dataTable.Columns.Count; foreach (DataRow row in dataTable.Rows) { for (int i = 0; i < cols; i++) { object val = row[i]; if (val is double) sum += (double)val; } } return sum; } } }
我们总是使用Excel Interop打开电子表格并直接parsing(例如,类似于如何通过VBA中的单元格进行扫描),或者我们创build了locking模板,在用户保存数据之前强制执行某些列填充。
你可以看看ExcelMapper。 这是一个读取强types对象的Excel文件的工具。 它隐藏了从代码中读取excel的所有细节。 如果您的Excel缺less列或列中缺less数据,那么请注意。 您可以阅读您感兴趣的数据。您可以从http://code.google.com/p/excelmapper/获取ExcelMapper的代码/可执行文件。
如果可能需要Excel表格的格式有列标题,那么你总是会有13列。 处理时只需要跳过标题行。
这也将纠正用户按照您不期望的顺序放置列的情况。 (检测标题行中的列索引并正确读取)
我发现其他人推荐Excel互操作,但与OleDb相比,这是一个缓慢的select。 另外它需要在服务器上安装Excel或OWC(许可)。
你可以尝试使用Excel和COM。 这样,你就可以直接从马的嘴里得到你的信息。
从D. Anand在MSDN论坛上:
在您的项目中创build一个引用到Excel对象库。 可以在添加引用对话框的COM选项卡中添加excel对象库。
以下是关于C#中Excel对象模型的一些信息http://msdn.microsoft.com/zh-cn/library/aa168292(office.11​).aspx
我build议您尝试使用Office和Excel Interop的Visual Studio工具! 它的使用是非常容易的。