【问题标题】:Optimal way to Read an Excel file (.xls/.xlsx)读取 Excel 文件 (.xls/.xlsx) 的最佳方式
【发布时间】:2012-10-21 08:36:10
【问题描述】:

我知道读取 Excel 文件有不同的方法:

  • Iterop
  • Oledb
  • Open Xml SDK

兼容性不是问题,因为程序将在受控环境中执行。

我的要求:
将文件读取到DataTable / CUstom Entities(我不知道如何为对象创建动态属性/字段[列名将在 Excel 文件中变化])

使用DataTable/Custom Entities 使用其数据执行一些操作。

使用操作结果更新DataTable

写回excel file

这样会更简单。

如果可能的话,也可以建议我自定义实体(动态地向对象添加属性/字段)

【问题讨论】:

  • @AmiramKorach 写回 excel 的基本原理....
  • 我为此使用了商业第三方。这已经在这里问了stackoverflow.com/questions/1527790/…
  • 我认为最有效的方法之一是使用 GemBox.Spreadsheet 库,它具有 export DataTable to sheetexporting sheet to DataTable 的直接方法。
  • 只是一点有用的建议,excel 文件只是 zip 文件。提取一个excel文件会给你留下几个文件夹。文件的字符串存储在“[filenamefolder]/xl/sharedStrings.xml”中,工作簿存储在“[filenamefolder]/xl/workbook.xml” 理论上,您可以通过编程方式解压缩 excel 文件并从中提取信息提取的文件。

标签: c# excel oledb openxml-sdk excel-interop


【解决方案1】:

看看Linq-to-Excel。挺好看的。

var book = new LinqToExcel.ExcelQueryFactory(@"File.xlsx");

var query =
    from row in book.Worksheet("Stock Entry")
    let item = new
    {
        Code = row["Code"].Cast<string>(),
        Supplier = row["Supplier"].Cast<string>(),
        Ref = row["Ref"].Cast<string>(),
    }
    where item.Supplier == "Walmart"
    select item;

它也允许强类型行访问。

【讨论】:

  • 请注意,Linq-to-Excel 使用第三方库列表。
  • @fschricker - 只有两个 - “log4net”和“Remotion”。
  • 还有 Access 数据库引擎,虽然 Microsoft 是另一个依赖项。
  • 虽然不错...由于“Access Database Engine”,这不是一个可行的生产资产。
  • 不要成为“巨魔”......但是......如果有人正在考虑使用它。您可以“可能”使用它的唯一地方是您自己的桌面。没有人会让您在客户端桌面或 Web 服务器上安装“Access Database Engine”……而且许多地方(有充分的理由)甚至不允许您在本地安装类似的东西。再一次,我喜欢语法,我喜欢这个想法……但这不是一个广泛可行的解决方案。仍然......非常酷。
【解决方案2】:

我意识到这个问题是近 7 年前提出的,但它仍然是某些关键字在使用 C# 导入 excel 数据时的热门搜索结果,因此我想根据最近的一些技术发展提供一个替代方案。

导入 Excel 数据已成为我日常工作中的一项常见任务,我已简化流程并将方法记录在我的博客上:best way to read excel file in c#

我使用NPOI,因为它可以在没有安装 Microsoft Office 的情况下读取/写入 Excel 文件,并且它不使用 COM+ 或任何互操作。这意味着它可以在云端运行!

但真正的魔力来自与 NPOI Mapper from Donny Tian 配对,因为它允许我将 Excel 列映射到我的 C# 类中的属性,而无需编写任何代码。很漂亮。

基本思路如下:

我创建了一个匹配/映射我感兴趣的 Excel 列的 .net 类:

        class CustomExcelFormat
        {
            [Column("District")]
            public int District { get; set; }

            [Column("DM")]
            public string FullName { get; set; }

            [Column("Email Address")]
            public string EmailAddress { get; set; }

            [Column("Username")]
            public string Username { get; set; }

            public string FirstName
            {
                get
                {
                    return Username.Split('.')[0];
                }
            }

            public string LastName
            {
                get
                {
                    return Username.Split('.')[1];
                }
            }
        }

注意,如果我愿意,它允许我根据列名进行映射!

然后,当我处理 excel 文件时,我需要做的就是这样:

        public void Execute(string localPath, int sheetIndex)
        {
            IWorkbook workbook;
            using (FileStream file = new FileStream(localPath, FileMode.Open, FileAccess.Read))
            {
                workbook = WorkbookFactory.Create(file);
            }

            var importer = new Mapper(workbook);
            var items = importer.Take<CustomExcelFormat>(sheetIndex);
            foreach(var item in items)
            {
                var row = item.Value;
                if (string.IsNullOrEmpty(row.EmailAddress))
                    continue;

                UpdateUser(row);
            }

            DataContext.SaveChanges();
        }

现在,诚然,我的代码不会修改 Excel 文件本身。相反,我使用 Entity Framework 将数据保存到数据库中(这就是您在我的示例中看到“UpdateUser”和“SaveChanges”的原因)。但是关于如何save/modify a file using NPOI的SO已经有了很好的讨论。

【讨论】:

  • 这就像一个魅力!迄今为止最简单的解决方案。两者都可以作为 NuGet 包使用。
  • 嗨,丹,如果没有服务器中的 excel 软件或 oledb 驱动程序,我无法解决 excel 文件处理问题。但是使用它,我能够实现。性能也不错。非常感谢。
  • 如何在不知道列名的情况下将其用于通用 excel 文件?例如,我宁愿将工作表导出到 DataTable 中。
  • David Pio - 使用新的 dynamic 功能。我想这就是你要找的。 mapper.Take&lt;dynamic&gt;(0).ToList();
  • 太棒了,像魅力一样工作,节省了大量时间。谢谢!
【解决方案3】:

使用 OLE 查询,非常简单(例如 sheetName 是 Sheet1):

DataTable LoadWorksheetInDataTable(string fileName, string sheetName)
{           
    DataTable sheetData = new DataTable();
    using (OleDbConnection conn = this.returnConnection(fileName))
    {
       conn.Open();
       // retrieve the data using data adapter
       OleDbDataAdapter sheetAdapter = new OleDbDataAdapter("select * from [" + sheetName + "$]", conn);
       sheetAdapter.Fill(sheetData);
       conn.Close();
    }                        
    return sheetData;
}

private OleDbConnection returnConnection(string fileName)
{
    return new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileName + "; Jet OLEDB:Engine Type=5;Extended Properties=\"Excel 8.0;\"");
}

对于较新的 Excel 版本:

return new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Extended Properties=Excel 12.0;");

您还可以使用 CodePlex 上的开源项目Excel Data Reader。它非常适合从 Excel 工作表中导出数据。

指定链接上给出的示例代码:

FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read);

//1. Reading from a binary Excel file ('97-2003 format; *.xls)
IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);
//...
//2. Reading from a OpenXml Excel file (2007 format; *.xlsx)
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
//...
//3. DataSet - The result of each spreadsheet will be created in the result.Tables
DataSet result = excelReader.AsDataSet();
//...
//4. DataSet - Create column names from first row
excelReader.IsFirstRowAsColumnNames = true;
DataSet result = excelReader.AsDataSet();

//5. Data Reader methods
while (excelReader.Read())
{
//excelReader.GetInt32(0);
}

//6. Free resources (IExcelDataReader is IDisposable)
excelReader.Close();

参考:How do I import from Excel to a DataSet using Microsoft.Office.Interop.Excel?

【讨论】:

【解决方案4】:

尝试使用这种免费方式,https://freenetexcel.codeplex.com

 Workbook workbook = new Workbook();

 workbook.LoadFromFile(@"..\..\parts.xls",ExcelVersion.Version97to2003);
 //Initialize worksheet
 Worksheet sheet = workbook.Worksheets[0];

 DataTable dataTable = sheet.ExportDataTable();

【讨论】:

【解决方案5】:

如果您可以将其限制为仅(Open Office XML 格式)*.xlsx 文件,那么最流行的库可能是EPPLus

奖励是,没有其他依赖项。只需使用 nuget 安装:

Install-Package EPPlus

【讨论】:

    【解决方案6】:

    尝试使用Aspose.cells库(不是免费的,但是试用版就够了),挺好的

    Install-package Aspose.cells

    有示例代码:

    using Aspose.Cells;
    using System;
    
    namespace ExcelReader
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Replace path for your file
                readXLS(@"C:\MyExcelFile.xls"); // or "*.xlsx"
                Console.ReadKey();
            }
    
            public static void readXLS(string PathToMyExcel)
            {
                //Open your template file.
                Workbook wb = new Workbook(PathToMyExcel);
    
                //Get the first worksheet.
                Worksheet worksheet = wb.Worksheets[0];
    
                //Get cells
                Cells cells = worksheet.Cells;
    
                // Get row and column count
                int rowCount = cells.MaxDataRow;
                int columnCount = cells.MaxDataColumn;
    
                // Current cell value
                string strCell = "";
    
                Console.WriteLine(String.Format("rowCount={0}, columnCount={1}", rowCount, columnCount));
    
                for (int row = 0; row <= rowCount; row++) // Numeration starts from 0 to MaxDataRow
                {
                    for (int column = 0; column <= columnCount; column++)  // Numeration starts from 0 to MaxDataColumn
                    {
                        strCell = "";
                        strCell = Convert.ToString(cells[row, column].Value);
                        if (String.IsNullOrEmpty(strCell))
                        {
                            continue;
                        }
                        else
                        {
                            // Do your staff here
                            Console.WriteLine(strCell);
                        }
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 它不是免费的,并且在完成一些解析后有许可证限制(我猜是 1K 左右)
    【解决方案7】:

    从excel中读取、修改并回写

     /// <summary>
    /// /Reads an excel file and converts it into dataset with each sheet as each table of the dataset
    /// </summary>
    /// <param name="filename"></param>
    /// <param name="headers">If set to true the first row will be considered as headers</param>
    /// <returns></returns>
    public DataSet Import(string filename, bool headers = true)
    {
        var _xl = new Excel.Application();
        var wb = _xl.Workbooks.Open(filename);
        var sheets = wb.Sheets;
        DataSet dataSet = null;
        if (sheets != null && sheets.Count != 0)
        {
            dataSet = new DataSet();
            foreach (var item in sheets)
            {
                var sheet = (Excel.Worksheet)item;
                DataTable dt = null;
                if (sheet != null)
                {
                    dt = new DataTable();
                    var ColumnCount = ((Excel.Range)sheet.UsedRange.Rows[1, Type.Missing]).Columns.Count;
                    var rowCount = ((Excel.Range)sheet.UsedRange.Columns[1, Type.Missing]).Rows.Count;
    
                    for (int j = 0; j < ColumnCount; j++)
                    {
                        var cell = (Excel.Range)sheet.Cells[1, j + 1];
                        var column = new DataColumn(headers ? cell.Value : string.Empty);
                        dt.Columns.Add(column);
                    }
    
                    for (int i = 0; i < rowCount; i++)
                    {
                        var r = dt.NewRow();
                        for (int j = 0; j < ColumnCount; j++)
                        {
                            var cell = (Excel.Range)sheet.Cells[i + 1 + (headers ? 1 : 0), j + 1];
                            r[j] = cell.Value;
                        }
                        dt.Rows.Add(r);
                    }
    
                }
                dataSet.Tables.Add(dt);
            }
        }
        _xl.Quit();
        return dataSet;
    }
    
    
    
     public string Export(DataTable dt, bool headers = false)
        {
            var wb = _xl.Workbooks.Add();
            var sheet = (Excel.Worksheet)wb.ActiveSheet;
            //process columns
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                var col = dt.Columns[i];
                //added columns to the top of sheet
                var currentCell = (Excel.Range)sheet.Cells[1, i + 1];
                currentCell.Value = col.ToString();
                currentCell.Font.Bold = true;
                //process rows
                for (int j = 0; j < dt.Rows.Count; j++)
                {
                    var row = dt.Rows[j];
                    //added rows to sheet
                    var cell = (Excel.Range)sheet.Cells[j + 1 + 1, i + 1];
                    cell.Value = row[i];
                }
                currentCell.EntireColumn.AutoFit();
            }
            var fileName="{somepath/somefile.xlsx}";
            wb.SaveCopyAs(fileName);
            _xl.Quit();
            return fileName;
        }
    

    【讨论】:

    • 什么是_xl.Workbooks?
    猜你喜欢
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 2018-11-27
    • 1970-01-01
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多