从C#读取Excel文件


233

是否有免费或开放源代码库可直接从C#程序读取Excel文件(.xls)?

不必太花哨,只需选择一个工作表并以字符串形式读取数据。到目前为止,我一直在使用Excel的“导出到Unicode文本”功能,并分析生成的(制表符分隔)文件,但是我想消除手动步骤。

Answers:


153
var fileName = string.Format("{0}\\fileNameHere", Directory.GetCurrentDirectory());
var connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0; data source={0}; Extended Properties=Excel 8.0;", fileName);

var adapter = new OleDbDataAdapter("SELECT * FROM [workSheetNameHere$]", connectionString);
var ds = new DataSet();

adapter.Fill(ds, "anyNameHere");

DataTable data = ds.Tables["anyNameHere"];

这就是我通常使用的。有点不同,因为我通常在表的编辑中粘贴一个AsEnumerable():

var data = ds.Tables["anyNameHere"].AsEnumerable();

因为这使我可以使用LINQ从字段中搜索和构建结构。

var query = data.Where(x => x.Field<string>("phoneNumber") != string.Empty).Select(x =>
                new MyContact
                    {
                        firstName= x.Field<string>("First Name"),
                        lastName = x.Field<string>("Last Name"),
                        phoneNumber =x.Field<string>("Phone Number"),
                    });

如果看起来像这种方法中的Select尝试猜测该列的数据类型,并强加于该猜测的数据类型。例如,如果您的一列中大多数都是双精度值,那么它将不希望您传递x.Field <string>,而是希望使用x.Field <double>。这是真的?
Kevin Le-Khnle 2010年

1
只是在MSDN上查询了一下。看起来<T>仅用于尝试将列中的内容强制转换为类型。在此示例中,仅将列中的数据转换为字符串。如果您想要一个double,则需要调用double.Parse(x.Field <string>(“ Cost”)或类似的东西。Field是DataRow的扩展方法,看起来好像没有一个非通用版本。
罗宾·罗宾逊

在Linq查询中添加double.Parse是否会使其速度大大降低?
匿名类型

23
请注意,如果您正在阅读xlsx,则需要改用以下连接字符串:string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}; Extended Properties=Excel 12.0;", fileName)
Andreas Grech 2012年

7
遗憾的是,Jet.OLEDB驱动程序不兼容64位。您将需要切换到目标x86而不是任何CPU(如果您仍然想继续使用此方法)。可替换地安装64位ACE驱动程序并更改康恩串以使用该驱动器(由Andreas所示) - microsoft.com/en-us/download/...
邓肯

83

如果只是Excel文件中包含的简单数据,则可以通过ADO.NET读取数据。请参阅此处列出的连接字符串:

http://www.connectionstrings.com/?carrier=excel2007http://www.connectionstrings.com/?carrier=excel

-瑞安

更新:然后您可以通过类似的方式阅读工作表 select * from [Sheet1$]


1
这种方式到目前为止是最快的。
2009年

17
当然不对,St。您必须筛选所有数据并编写糟糕的DB代码(手工制作模型,将列映射到属性,yadda yadda)。最快的方法是让其他可怜的SOB为您执行此操作。这就是为什么人们使用框架而不是从头开始编写所有内容的原因。

12
不值钱的方法!读取时将文本列截断为255个字符。谨防!请参阅:stackoverflow.com/questions/1519288/…ACE 引擎具有相同功能!
Triynko 2010年

5
请注意,使用ADO.NET从exel读取数据需要安装Microsoft Access或Microsoft Access数据库引擎可再发行组件。
zihotki 2011年

3
驱动程序还将基于前几行猜测列类型。如果您在第一行中有一列看起来像整数的列,则在您遇到非整数(例如,浮点数,字符串)时会遇到错误
Brian Low


22

这是我用于Excel 2003的内容:

Dictionary<string, string> props = new Dictionary<string, string>();
props["Provider"] = "Microsoft.Jet.OLEDB.4.0";
props["Data Source"] = repFile;
props["Extended Properties"] = "Excel 8.0";

StringBuilder sb = new StringBuilder();
foreach (KeyValuePair<string, string> prop in props)
{
    sb.Append(prop.Key);
    sb.Append('=');
    sb.Append(prop.Value);
    sb.Append(';');
}
string properties = sb.ToString();

using (OleDbConnection conn = new OleDbConnection(properties))
{
    conn.Open();
    DataSet ds = new DataSet();
    string columns = String.Join(",", columnNames.ToArray());
    using (OleDbDataAdapter da = new OleDbDataAdapter(
        "SELECT " + columns + " FROM [" + worksheet + "$]", conn))
    {
        DataTable dt = new DataTable(tableName);
        da.Fill(dt);
        ds.Tables.Add(dt);
    }
}

2
工作表未定义...在清楚定义其他所有内容后,我觉得有些奇怪。
杰里米·霍洛瓦奇

21

Excel Data Reader怎么样?

http://exceldatareader.codeplex.com/

我曾在生产环境中使用它来将大量数据从各种Excel文件中提取到SQL Server Compact中。它工作得很好,并且非常健壮。


2
我将第二个Excel数据读取器;它还导致了非常有用的Excel数据驱动测试库,该库使用NUnit 2.5的TestCaseSource属性使使用Excel电子表格的数据驱动测试变得异常容易。请注意,Resharper还不支持TestCaseSource,因此您必须使用NUnit运行器。
David Keaveny

不幸的是,我们刚遇到该库的一些问题。首先,我们有一些货币字段作为日期出现。其次,如果工作簿中有任何空白表,则崩溃。因此,尽管集成起来非常容易,但是我们现在正在重新评估是否继续使用该库。它似乎没有得到积极开发。
Ian1971

它还假定xlsx文件中存在一些可选元素,如果缺少这些元素,则它们将无法读取数据。
RichieHindle 2012年

我们遇到了来自SQL Server Reporting Services的Excel文件的问题。它们只是不起作用,除非您将其打开并保存(甚至未经编辑)。@RichieHindle:您在谈论什么可选元素(希望这对我的SSRS Excel文件有帮助)?
彼得

@Peter:我认为这是一个缺失的<dimension>因素,<worksheet>给我造成了麻烦。
RichieHindle

16

这是几年前我使用.NET 1.1在C#中编写的一些代码。不知道这是否正是您所需要的(可能不是我最好的代码:)。

using System;
using System.Data;
using System.Data.OleDb;

namespace ExportExcelToAccess
{
    /// <summary>
    /// Summary description for ExcelHelper.
    /// </summary>
    public sealed class ExcelHelper
    {
        private const string CONNECTION_STRING = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=<FILENAME>;Extended Properties=\"Excel 8.0;HDR=Yes;\";";

        public static DataTable GetDataTableFromExcelFile(string fullFileName, ref string sheetName)
        {
            OleDbConnection objConnection = new OleDbConnection();
            objConnection = new OleDbConnection(CONNECTION_STRING.Replace("<FILENAME>", fullFileName));
            DataSet dsImport = new DataSet();

            try
            {
                objConnection.Open();

                DataTable dtSchema = objConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);

                if( (null == dtSchema) || ( dtSchema.Rows.Count <= 0 ) )
                {
                    //raise exception if needed
                }

                if( (null != sheetName) && (0 != sheetName.Length))
                {
                    if( !CheckIfSheetNameExists(sheetName, dtSchema) )
                    {
                        //raise exception if needed
                    }
                }
                else
                {
                    //Reading the first sheet name from the Excel file.
                    sheetName = dtSchema.Rows[0]["TABLE_NAME"].ToString();
                }

                new OleDbDataAdapter("SELECT * FROM [" + sheetName + "]", objConnection ).Fill(dsImport);
            }
            catch (Exception)
            {
                //raise exception if needed
            }
            finally
            {
                // Clean up.
                if(objConnection != null)
                {
                    objConnection.Close();
                    objConnection.Dispose();
                }
            }


            return dsImport.Tables[0];
            #region Commented code for importing data from CSV file.
            //              string strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" +"Data Source=" + System.IO.Path.GetDirectoryName(fullFileName) +";" +"Extended Properties=\"Text;HDR=YES;FMT=Delimited\"";
            //
            //              System.Data.OleDb.OleDbConnection conText = new System.Data.OleDb.OleDbConnection(strConnectionString);
            //              new System.Data.OleDb.OleDbDataAdapter("SELECT * FROM " + System.IO.Path.GetFileName(fullFileName).Replace(".", "#"), conText).Fill(dsImport);
            //              return dsImport.Tables[0];

            #endregion
        }

        /// <summary>
        /// This method checks if the user entered sheetName exists in the Schema Table
        /// </summary>
        /// <param name="sheetName">Sheet name to be verified</param>
        /// <param name="dtSchema">schema table </param>
        private static bool CheckIfSheetNameExists(string sheetName, DataTable dtSchema)
        {
            foreach(DataRow dataRow in dtSchema.Rows)
            {
                if( sheetName == dataRow["TABLE_NAME"].ToString() )
                {
                    return true;
                }   
            }
            return false;
        }
    }
}

完全同意Cherian。该代码已有多年历史了……在我还没有精通Resharper之前:)
hitec

2
代码很丑陋,但是它显示了如何获取工作表名称,太好了!
山姆



8

前一段时间,我从C#中的Excel文件中进行了大量读取,我们使用了两种方法:

  • COM API,您可以在其中直接访问Excel的对象并通过方法和属性对其进行操作
  • 允许像数据库一样使用Excel的ODBC驱动程序。

后一种方法快得多:通过COM读取包含20列和200行的大表将花费30秒,而通过ODBC将花费半秒。因此,如果您需要的只是数据,我建议使用数据库方法。

干杯,

卡尔



6

我想展示一种使用.NET读取xls / xlsx文件的简单方法。希望以下内容对您有所帮助。

 私有DataTable ReadExcelToTable(字符串路径)    
 {

     //连接字符串

     string connstring =“ Provider = Microsoft.ACE.OLEDB.12.0; Data Source =” + path +“;扩展属性='Excel 8.0; HDR = NO; IMEX = 1';”;  
     //同名 
     // string connstring = Provider = Microsoft.JET.OLEDB.4.0; Data Source =“ + path + //”;扩展属性='Excel 8.0; HDR = NO; IMEX = 1';“; 

     using(OleDbConnection conn =新的OleDbConnection(connstring))
     {
        conn.Open();
        //获取所有工作表名称
        DataTablesheetName = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,new object [] {null,null,null,“ Table”});  

        //获取第一个工作表名称
        字符串firstSheetName = sheetName.Rows [0] [2] .ToString(); 

        //请求参数 
        字符串sql = string.Format(“ SELECT * FROM [{0}]”,firstSheetName); 
        OleDbDataAdapter ada =新OleDbDataAdapter(sql,connstring);
        DataSet set = new DataSet();
        ada.Fill(set);
        返回set.Tables [0];   
   }
 }

代码来自文章:http : //www.c-sharpcorner.com/uploadfile/d2dcfc/read-excel-file-with-net/。您可以从中获取更多详细信息。


2
有帮助的,尤其是关于阅读的sheetnames的一部分。
martinstoeckli 2012年

4

它不是免费的,但是使用最新的Office会有一个非常不错的自动化.Net API。(已经存在API已有很长时间了,但是它却是令人讨厌的COM),而Office应用程序仍然是一个隐藏的后台进程,则可以在代码中完成所有想要/需要的事情。


3
@ Anonymous-type我确实读过这个问题,并且为所需的OSS实现提供了一个有用的替代方法……因为,我很确定没有可用的方法。并且,从接受的答案来看,安装Office的要求不是问题。
xanadont 2010年

3

如果我不在这里,请原谅我,但这不是Office PIA的目的吗?


5
是的,但是那将涉及创建Excel.Application实例,加载xls文件等。如果仅是从文件中读取一些数据的要求,则使用所描述的ADO.NET方法之一将更加容易,而且轻巧得多。在其他答案中。
亚当·拉尔夫

太慢了,使用Office PIA作为基准,其他所有操作都更快-甚至只是使用从.Value2属性传递的Object数组。哪些仍在使用PIA。
匿名类型

3

最近,部分是为了使LINQ更好。...我一直在使用Excel的自动化API将文件保存为XML Spreadsheet,然后使用LINQ to XML处理该文件。


我怀疑您可以从Excel中保护它,但不能从带有编译器的人那里保护它……像其他任何东西……仅仅是字节。
肯尼,2010年

@gsvirdi,发布有关Excel文件安全性的单独问题,该问题与性能有关。
匿名类型


3

SmartXLS是另一个excel电子表格组件,它支持excel图表的大多数功能,公式引擎,并且可以读取/写入excel2007 openxml格式。



2

我建议使用FileHelpers库,它是一个免费且易于使用的.NET库,用于从EXCEL,文件中的定长或定界记录,字符串或流中导入/导出数据,字符串或流以及更多内容。

Excel数据链接文档部分 http://filehelpers.sourceforge.net/example_exceldatalink.html


1
我不会拒绝您的,但是我最近开始使用FileHelpers,但对它的糟糕程度感到震惊。例如,将csv中的列映射到属性的唯一方法...对不起,模型的FIELDS是按列的顺序创建字段。我不了解您,但对于我的f8king框架最主要的设计考虑因素之一,我不会依赖于编译器的怪癖。


2

SpreadsheetGear很棒。是的,这是一种支出,但是与花钱与其他解决方案相比,这是值得的。它快速,可靠,非常全面,我必须说在我的全职软件工作中使用此产品一年半之后,他们的客户支持非常棒!


当有许多简单有效的方法(免费)来读取和写入Excel时,很难证明这一点。
匿名类型

2

我们使用的解决方案需要:

  • 允许读取/写入 Excel产生的文件
  • 快速的性能(不喜欢使用COM口)
  • 独立于MS Office的(需要在没有安装MS Office的客户端的情况下可用)
  • 免费的还是开源的(但积极开发)

有多种选择,但是我们发现NPoi(Java长期存在的Poi开源项目的.NET端口)是最好的:http : //npoi.codeplex.com/

它还允许使用.doc和.ppt文件格式


2

如果只是表格数据。我会推荐Marcos Melli提供的文件数据助手,可以在这里下载。



1

您可以编写一个Excel电子表格,该电子表格可以加载给定的Excel电子表格并将其保存为csv(而不是手动执行)。

那么您可以通过c#将其自动化。

并且一旦在csv中,C#程序就可以解决该问题。

(此外,如果有人要求您使用excel编程,最好假装您不知道如何操作)

(编辑:是的,抢劫和瑞安都是对的)




1

Excel Package是用于读取/写入Excel 2007文件的开源(GPL)组件。我在一个小项目上使用了它,API很简单。仅适用于XLSX(Excel 200&),不适用于XLS。

源代码看起来也井井有条,易于解决(如果您需要像我一样扩展功能或解决小问题)。

最初,我尝试使用ADO.Net(Excel连接字符串)方法,但此方法充满了讨厌的骇客-例如,如果第二行包含数字,它将为下面列中的所有字段返回整数,并静默删除任何数据那不合适。


1

我们在相当大的系统中使用ClosedXML

  • 自由
  • 易于安装
  • 直接编码
  • 非常及时的支持
  • 开发人员团队非常乐意接受新建议。通常会在同一周内实施新功能和错误修复

1

Take.io电子表格将为您免费完成此工作。看看这个


这是一个非常棒的小图书馆。它只是将所有内容都转换为字符串列表,这对于我需要它的工作来说是很好的。
Drewmate 2012年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.