从 C 读取 Excel 文件#

Reading Excel files from C#

提问人:dbkk 提问时间:8/19/2008 最后编辑:Chrisdbkk 更新时间:12/23/2012 访问量:530654

问:

锁定。这个问题及其答案被锁定,因为这个问题偏离了主题,但具有历史意义。它目前不接受新的答案或互动。

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

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

C# .NET Excel MS-Office

评论


答:

1赞 Leon Bambrick #1

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

然后,您可以从 C# 中自动执行此操作。

一旦它进入 CSV,C# 程序就可以解决这个问题。

(另外,如果有人要求您在 Excel 中编程,最好假装不知道怎么做)

(编辑:啊,是的,Rob 和 Ryan 都是对的)

1赞 Lars Mæhlum #2

我知道人们一直在为此目的制作 Excel“扩展”。
您或多或少地在 Excel 中创建一个按钮,上面写着“导出到程序 X”,然后以程序可以读取的格式导出和发送数据。

http://msdn.microsoft.com/en-us/library/ms186213.aspx 应该是一个很好的起点。

祝你好运

3赞 Rob Cooper #3

请原谅我是否在这里,但这不正是 Office PIA 的用途吗?

评论

5赞 Adam Ralph 1/20/2009
是的,但这涉及创建 Excel.Application 实例、加载 xls 文件等。如果要求纯粹是从文件中读取一些数据,那么使用其他答案中描述的 ADO.NET 方法之一要容易得多,也轻量级得多。
0赞 Anonymous Type 12/20/2010
太慢了,使用 Office PIA 作为基线,其他一切都更快 - 即使只是使用从 .Value2 属性。它仍在使用 PIA。
83赞 2 revsRyan Farley #4

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

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

-莱恩

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

评论

1赞 StingyJack 1/19/2009
这种方式是迄今为止最快的。
17赞 11/28/2009
当然不是真的,吝啬。你必须筛选所有数据并编写蹩脚的数据库代码(手工制作模型,将列映射到属性,yadda yadda)。最快的方法是让其他一些可怜的 SOB 为您做这件事。这就是为什么人们使用框架而不是自下而上编写所有内容的原因。
12赞 Triynko 5/14/2010
毫无价值的方法!读取时将文本列截断为 255 个字符。小心!请参见:stackoverflow.com/questions/1519288/...ACE引擎做同样的事情!
5赞 zihotki 1/6/2011
请注意,使用 ADO.NET 从 exel 读取数据需要安装 Microsoft Access 或 Microsoft Access 数据库引擎可再发行组件。
3赞 Brian Low 4/14/2011
驱动程序还将根据前几行猜测列类型。如果你的列在第一行中看起来像整数,那么当你遇到一个非整数(例如浮点数、字符串)时,你会遇到一个错误
4赞 xanadont #5

不是免费的,但最新的 Office 有一个非常好的自动化 .Net API。(有一个 API 已经有一段时间了,但很讨厌 COM)你可以在代码中执行任何想要/需要的事情,而 Office 应用仍然是一个隐藏的后台进程。

评论

3赞 xanadont 12/21/2010
@Anonymous类型我确实阅读了这个问题,并为所需的 OSS 实现提供了一个有用的替代方案......因为,好吧,我很确定没有可用的。而且,从公认的答案来看,安装 Office 的要求不是问题。
1赞 Christian Hagelid #6

刚刚做了一个快速演示项目,需要管理一些 excel 文件。GemBox 软件的 .NET 组件足以满足我的需求。它有一个免费版本,但有一些限制。

http://www.gemboxsoftware.com/GBSpreadsheet.htm

评论

0赞 Chad 10/11/2012
仅供参考:我试过了,它不符合我能够读取加密文件的需求。
16赞 hitec #7

这是我几年前使用 .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;
        }
    }
}

评论

0赞 hitec 7/14/2009
不能同意更多的切里安。这段代码已经很多年了......在我甚至精通 Resharper :) 之前
2赞 Sam 7/23/2010
代码很丑陋,但它显示了如何获取工作表名称,太棒了!
152赞 Robin Robinson #8
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"),
                    });

评论

0赞 Kevin Le - Khnle 6/3/2010
如果此方法中的 Select 似乎尝试猜测列的数据类型并强制该猜测的数据类型。例如,如果您的列主要包含双精度值,则它不会像您传递 x.Field<string>,而是需要 x.Field<double>。这是真的吗?
1赞 Robin Robinson 6/4/2010
刚刚在MSDN上查了一下。看起来 <T> 只是用于尝试将列中的内容强制转换为类型。在此示例中,仅将列中的数据转换为字符串。如果你想要一个双倍,你需要打电话给双倍。Parse(x.Field<string>(“Cost”) 或类似的东西。Field 是 DataRow 的扩展方法,看起来没有非通用版本。
0赞 Anonymous Type 12/20/2010
添加双倍。解析到 Linq 查询会减慢它的速度吗?
23赞 Andreas Grech 3/11/2012
请注意,如果正在阅读 ,则需要改用此连接字符串:xlsxstring.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}; Extended Properties=Excel 12.0;", fileName)
7赞 Duncan 6/7/2012
遗憾的是,Jet.OLEDB 驱动程序与 64 位不兼容;您需要切换到目标 x86 而不是任何 CPU(如果您仍想继续使用此方法)。或者,安装 64 位 ACE 驱动程序并更改连接字符串以使用此驱动程序(如 Andreas 所示) - microsoft.com/en-us/download/...
27赞 Ian Nelson #9

ADO.NET 方法既快速又简单,但它有一些你应该注意的怪癖,特别是关于如何处理数据类型。

这篇优秀的文章将帮助您避免一些常见的陷阱: http://blog.lab49.com/archives/196

评论

0赞 Kevin Le - Khnle 6/3/2010
你回答了我的问题(以上面评论的形式)。
8赞 Carl Seleborg #10

不久前,我在 C# 中从 Excel 文件中进行了大量阅读,我们使用了两种方法:

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

后一种方法要快得多:通过 COM 读取一个包含 20 列和 200 行的大表需要 30 秒,通过 ODBC 需要半秒。因此,如果您只需要数据,我会推荐数据库方法。

干杯

卡尔

12赞 Hafthor #11

虽然您确实特别要求.xls,这意味着较旧的文件格式,但对于 OpenXML 格式(例如.xlsx),我强烈推荐 OpenXML SDK (http://msdn.microsoft.com/en-us/library/bb448854.aspx)

2赞 Jason Von Ruden #12

我推荐 FileHelpers 库,这是一个免费且易于使用的 .NET 库,用于从 EXCEL、文件、字符串或流中的固定长度或分隔记录 + 更多中导入/导出数据。

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

评论

1赞 11/28/2009
我不会贬低你,但我最近开始使用 FileHelpers,并对如何......它很糟糕。例如,将 csv 中的列映射到属性的唯一方法...对不起,FIELDS,模型是按列的顺序创建字段。我不了解你,但我不会依赖编译器的怪癖来作为我的 f8king 框架最核心的设计考虑因素之一。
3赞 kenny #13

最近,部分原因是为了在 LINQ 上做得更好......我一直在使用 Excel 的自动化 API 将文件另存为 XML 电子表格,然后使用 LINQ to XML 处理该文件。

评论

0赞 kenny 5/26/2010
我怀疑您可以保护它免受 Excel 的侵害,但不能保护它免受编译器的侵害......像任何东西一样......它只是字节。
0赞 Anonymous Type 12/20/2010
@gsvirdi,发布一个关于Excel文件安全性的单独问题,这个问题是关于性能的。
22赞 Dmitry Shechtman #14

这是我用于 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赞 Jeremy Holovacs 7/19/2011
工作表未定义...在明确定义了其他所有内容之后,对我来说似乎有点奇怪。
15赞 2 revsRune Grimstad #15

Koogra 是一个用 C# 编写的开源组件,用于读取和写入 Excel 文件。

评论

0赞 David Burton 8/15/2012
与NPOI相比,看起来不再特别活跃
3赞 Joe Erickson #16

SpreadsheetGear for .NET 是用于 .NET 的 Excel 兼容电子表格组件。您可以在我们产品页面的右侧查看客户对性能的评价。您可以通过免费的全功能评估自行尝试。

6赞 2 revsanonymous #17

ExcelMapper 是一个开源工具 (http://code.google.com/p/excelmapper/),可用于将 Excel 工作表读取为强类型对象。它支持 xls 和 xlsx 格式。

0赞 Hafthor #18

我刚刚使用 ExcelLibrary 将 .xls 电子表格加载到 DataSet 中。对我来说效果很好。

3赞 liya #19

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

1赞 dbkk #20

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

源代码似乎也井井有条且易于处理(如果您需要像我一样扩展功能或修复小问题)。

起初,我尝试了 ADO.Net(Excel 连接字符串)方法,但它充满了令人讨厌的黑客——例如,如果第二行包含一个数字,它将返回下面列中所有字段的整数,并悄悄地删除任何不合适的数据。

2赞 user289261 #21

您可以尝试使用此开源解决方案,该解决方案使处理 Excel 变得更加简洁。

http://excelwrapperdotnet.codeplex.com/

2赞 John R #22

SpreadsheetGear 很棒。是的,这是一笔费用,但与摆弄这些其他解决方案相比,这是值得的。它快速、可靠、非常全面,我不得不说,在我的全职软件工作中使用了这个产品一年半多后,他们的客户支持太棒了!

评论

0赞 Anonymous Type 12/20/2010
当有这么多简单有效的方法(免费)读取和写入 Excel 时,很难证明是合理的。
21赞 Michał Pawłowski #23

Excel Data Reader怎么样?

http://exceldatareader.codeplex.com/

在生产环境中,我使用愤怒将大量数据从各种 Excel 文件提取到 SQL Server Compact 中。它运行良好,而且相当强大。

评论

2赞 David Keaveny 10/20/2010
我将第二个 Excel 数据读取器;它还导致了非常有用的 Excel 数据驱动测试库,该库使用 NUnit 2.5 的 TestCaseSource 属性使使用 Excel 电子表格的数据驱动测试变得非常容易。请注意,Resharper 尚不支持 TestCaseSource,因此您必须使用 NUnit 运行器。
0赞 Ian1971 10/23/2012
不幸的是,我们刚刚遇到了这个库的一些问题。首先,我们有一些货币字段作为日期出现。其次,如果工作簿中有任何空工作表,它就会崩溃。因此,尽管它很容易集成,但我们现在正在重新评估是否继续使用这个库。它似乎没有得到积极开发。
0赞 RichieHindle 12/20/2012
它还假定 xlsx 文件中存在一些可选元素,如果它们不存在,则会导致它无法读取数据。
0赞 Peter 1/14/2013
我们在处理来自 SQL Server Reporting Services 的 Excel 文件时遇到了问题。它们根本不起作用,除非您打开它们并保存它们(即使未经编辑)。@RichieHindle:你在说什么可选元素(希望这可以帮助我处理我的 SSRS Excel 文件)?
0赞 RichieHindle 1/14/2013
@Peter:我认为这是给我带来麻烦的一个缺失元素。<dimension><worksheet>
3赞 Bonnie Cornell #24

.NET 组件 Excel Reader .NET 可以满足您的要求。它足以读取 XLSX 和 XLS 文件。因此,请尝试:

http://www.devtriogroup.com/ExcelReader

2赞 Marcel Toth #25

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

  • 允许读取/写入 Excel 生成的文件
  • 性能要快(不像使用 COM)
  • 独立于 MS Office(需要在没有安装 MS Office 的客户端的情况下可用)
  • 是自由的或开源的(但积极开发)

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

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

2赞 cless #26

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

1赞 2 revs, 2 users 67%greeness #27

Take.io电子表格将为您完成这项工作,而且不收取任何费用。看看这个就知道了。

评论

0赞 Drewmate 11/29/2012
这是一个非常棒的小图书馆。它只是将所有内容转换为字符串列表的列表,这对于我需要它的工作来说很好。
6赞 2 revs, 2 users 95%Lizzy #28

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

 private DataTable ReadExcelToTable(string path)    
 {

     //Connection String

     string connstring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path + ";Extended Properties='Excel 8.0;HDR=NO;IMEX=1';";  
     //the same name 
     //string connstring = Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + path + //";Extended Properties='Excel 8.0;HDR=NO;IMEX=1';"; 

     using(OleDbConnection conn = new OleDbConnection(connstring))
     {
        conn.Open();
        //Get All Sheets Name
        DataTable sheetsName = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,new object[]{null,null,null,"Table"});  

        //Get the First Sheet Name
        string firstSheetName = sheetsName.Rows[0][2].ToString(); 

        //Query String 
        string sql = string.Format("SELECT * FROM [{0}]",firstSheetName); 
        OleDbDataAdapter ada =new OleDbDataAdapter(sql,connstring);
        DataSet set = new DataSet();
        ada.Fill(set);
        return set.Tables[0];   
   }
 }

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

评论

2赞 martinstoeckli 3/30/2012
这很有帮助,尤其是关于阅读床单名称的部分。
1赞 2 revsDoctor Rudolf #29

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

  • 自由
  • 易于安装
  • 直接编码
  • 反应灵敏的支持
  • 开发团队对新建议持非常开放的态度。通常,新功能和错误修复会在同一周内实现
2赞 DeeDee #30

聚会迟到了,但我是 LinqToExcel 的粉丝