【问题标题】:C#: XLS library needed after switching from 32BIT to 64BITC#:从 32BIT 切换到 64BIT 后需要 XLS 库
【发布时间】:2022-01-22 19:25:41
【问题描述】:

原始查询: 目前我想从 32 位版本切换到 64 位版本,但我无法找到任何库以从 xls 中提取数据。 我可以在 ClosedXML 上与 (xlsx, xlsm) 等其他人一起工作,不幸的是不支持 xls。

所以现在这种联系是站不住脚的。

    string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path + ";Extended Properties='Excel 12.0;HDR=NO,IMEX=1'";
    string excelQuery = "SELECT * FROM [monthly$A:G]";

为 OLE 安装 64 位驱动程序是不可能的。所以也许有人偶然发现了它,或者有任何想法。

我想将数据构建到数据表中,其标题类似于HDR=YES,并且可以像上面的示例一样将其关闭。

另外,由于 excel 格式,dapper 是不可能的:(

我试图找到一些问题,但我能找到的只是安装 64 位的 OLEDB 驱动程序。

编辑: 我不明白为什么有人会放弃 Panagiotis 的答案,因为它已得到纠正,这就是我接受它的原因。他建议使用ExcelDataReader 被证明是最有效的,因为我在应用程序中使用更多格式的excel,如.xlsx.xlsm.xlsb,另外还有一些.csv 文件。 这让我可以构建一个模块,这就足够了。

他指出.xls 是古老的,但不幸的是它并没有过时,因为我公司的许多流程仍然依赖它,这也是正确的。但它应该是过时的,不幸的是,由于流程计划不周,我们被卡住了,而不是因为.xls 很有用。尤其是那些公司应该注意不支持某些格式的事实,或者可能会失去这种支持,因为.xls 正在慢慢得到这种处理。

另一个编辑: 不幸的是,我刚刚注意到,我是菜鸟,我不知道可以支付 nugets。 Aspose,不幸的是,它是那些付费扩展之一。所以我不得不更改代码并添加另一个转换器类。 为此,我根据需要使用并修改了另一个 [thread ][1] 中使用的代码。

最后编辑:

好的,在更新到 ExcelDataReader 后,我对性能不满意,并且转换文件对我来说似乎不合适,因为我注意到 @MarkPflug 已更新 [Sylvan.Data.Excel][2]库,并且对基准印象深刻,我基于它编写了代码。有一些探险,但在联系并给马克提供了样本后,他很快就解决了这些问题。目前这是我能想到的最快最好的解决方案。

我将更新它以用于从选定的文件数量中异步提取。但基于此,任何人都可以使用它。

**FINAL CODE:**
using SylExcel = Sylvan.Data.Excel;
using SylCSV = Sylvan.Data.Csv;
using SylData = Sylvan.Data;
        /// <summary>
        /// get data from .csv, .xls, .xlsx, .xlsm, .xlsb. Call is then redirected accordingly
        /// </summary>
        /// <param name="_filePath">path to file needed</param>
        /// <param name="_sheetName">sheet name to extract</param>
        /// <param name="_structure">structure of needed file</param>
        public void GetData(string _filePath, string? _sheetName, FilesStructures.Structure _structure)
        {
            //if (CheckIfOpened(_filePath))
            //{
            //    throw new OperationCanceledException(_filePath + " is opened, please close it.");
            //}

            try
            {
                string extension = Path.GetExtension(_filePath);

                switch (extension)
                {
                    case ".csv":
                        SylvanReaderCSV(_filePath, _structure);
                        break;
                    default:
                        SylvanReader(_filePath, _sheetName, _structure);
                        break;
                }

                //collect file information
                GetMetadata(_filePath);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

        }
        /// <summary>
        /// sylvan reader for .xls, .xlsx, .xlsm, .xlsb
        /// </summary>
        /// <param name="_filePath">path to file needed</param>
        /// <param name="_sheetName">sheet name to extract</param>
        /// <param name="_structure">structure of needed file</param>
        /// <exception cref="Exception"></exception>
        private void SylvanReader(string _filePath, string? _sheetName, FilesStructures.Structure _structure)
        {
            try
            {

                string headerSchema = "";

                //get unique column list to test for duplicates
                List<string> columnList = new List<string>();

                //build headers
                //_structure.HeaderList = List<strings> passed by object _structure
                foreach (var header in _structure.HeaderList)
                {
                    if (!columnList.Exists(column => column == header))
                    {
                        headerSchema += header + ", ";
                        columnList.Add(header);
                    }
                }
                //remove last 2 chars
                headerSchema = headerSchema.Substring(0, headerSchema.Length - 2);
       

                var options = new SylExcel.ExcelDataReaderOptions { Schema = SylExcel.ExcelSchema.NoHeaders, GetErrorAsNull = true };
                //collect data
                using (SylExcel.ExcelDataReader excelDataReader = SylExcel.ExcelDataReader.Create(_filePath, options))
                {
                    //loop to locate sheet
                    while (excelDataReader.WorksheetName != _sheetName)
                    {
                        excelDataReader.NextResult();

                        if (excelDataReader.WorksheetName == null)
                        {
                            throw new Exception("didnt find the sheet");
                        }
                    }
                    //loop to find headers
                    for(int i = 0; i < _structure.StartRow; i++)
                    {
                        excelDataReader.Read();
                    }

                    // parse the schema, and use it to reinitialize the schema for the sheet.
                    var schema = SylData.Schema.Parse(headerSchema);
                    excelDataReader.InitializeSchema(schema.GetColumnSchema(), useHeaders: true);

                    DataTable = new DataTable();
                    DataTable.Load(excelDataReader);
                }
            }
            catch(Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        /// <summary>
        /// sylvan reader for .csv
        /// </summary>
        /// <param name="_filePath">path to file needed</param>
        /// <param name="_sheetName">sheet name to extract</param>
        /// <param name="_structure">structure of needed file</param>
        /// <exception cref="Exception"></exception>
        private void SylvanReaderCSV(string _filePath, FilesStructures.Structure _structure)
        {
            try
            {
                string headerSchema = "";

                //get unique column list to test for duplicates
                List<string> columnList = new List<string>();

                //build headers
                //_structure.HeaderList = List<strings> passed by object _structure
                foreach (var header in _structure.HeaderList)
                {
                    if (!columnList.Exists(column => column == header))
                    {
                        headerSchema += header + ", ";
                        columnList.Add(header);
                    }
                }

                //remove last 2 chars
                headerSchema = headerSchema.Substring(0, headerSchema.Length - 2);

                var schema = new SylCSV.CsvSchema(SylData.Schema.Parse(headerSchema));
                var options = new SylCSV.CsvDataReaderOptions //check if get error as null possible
                { 
                    Schema = schema,
                };
                using (SylCSV.CsvDataReader csvDataReader = SylCSV.CsvDataReader.Create(_filePath, options))
                {
                    DataTable = new DataTable();
                    DataTable.Load(csvDataReader);
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        } 


  [1]: https://stackoverflow.com/questions/28398071/reading-excel-xlsb-files-in-c-sharp
  [2]: https://github.com/MarkPflug/Sylvan.Data.Excel

【问题讨论】:

  • 不要以 XLS 开头。该格式在 2007 年被 xlsx 取代 - 那是 15 年前。 所有 Excel 版本使用xlsx,所有应用程序也是如此。不存在兼容性问题 - 事实上,导致兼容性问题的是古老的xls。例如,除非您付费,否则 Google 表格不支持 xls 文件
  • “为 OLE 安装 64 位驱动程序是不可能的”为什么?在提出替代解决方案之前了解约束条件会有所帮助。
  • 嘿,我都不能停止使用 xls 并安装 64 位驱动程序,这是因为我正在使用现有的基础架构,这超出了我的控制范围,如果由我决定,我们会首先不要使用 xls。

标签: c# wpf xls c#-5.0


【解决方案1】:

您可以查看我的图书馆Sylvan.Data.Excel。它没有外部依赖,是跨平台的、开源的、MIT 许可的,也是fastest Excel data reader for .NET。它通过相同的 API 同时支持 .xls、.xlsx 和 .xlsb。它不像其他一些库那样功能齐全,它只支持读取(不支持写入),但它应该是 ACE 的直接替代品,因为它实现了DbDataReader。如果您遇到任何问题/疑问,请随时在 GitHub 存储库中打开它们。

使用起来非常简单:


var edr = ExcelDataReader.Create("data.xls");

while(edr.Read()) {
  for(int i = 0; i < edr.FieldCount; i++) {
    var value = edr.GetString(i);
  }
}

默认情况下,它会期望每张工作表的第一行包含标题。然而,这可以被禁用。禁用时,列只能按序号访问。

var opts = new ExcelDataReaderOptions { Schema = ExcelSchema.NoHeaders };
var edr = ExcelDataReader.Create("data.xls", opts);

由于它实现了DbDataReader,因此将其加载到数据表中是单行的:

var dt = new DataTable();
dt.Load(edr);

【讨论】:

  • 我明天试试,如果它工作正常回复你:)
  • 你好,马克,我刚刚用 ExcelDataReader 完成了多次更改,虽然我看着你的 benchamrks 我想把它换给 Sylvan,但我不得不问:我在 GitHub 上看到你插入.xlsb Benchmarks,您最近是否添加了此功能,现在它支持.xlsb 没有依赖关系还是需要OLE 驱动程序?
  • 是的,我在周末添加了 .xlsb 支持。仍然没有外部依赖。如果您遇到问题,请随时通过 github repo 联系。只需确保您使用的是最新的预发布版本。我很快就会用 .xlsb 推送正式版本。
  • 好消息,我将在周五尝试使用 Sylvan 构建新模块并测试结果。但是最好不要将文件从xlsb 格式化为xlsx 你以后计划支持csv 吗?
  • 我有一个单独的库 Sylvan.Data.Csv 提供 CSV 支持。它也是 .NET 中最快的 CSV 解析器。 joelverhagen.com/blog/2020/12/fastest-net-csv-parsers
【解决方案2】:

首先,不要使用 XLS 开头。该格式在 2007 年被 xlsx 取代 - 那是 15 年前。 所有 Excel 版本使用xlsx,所有应用程序也是如此。没有兼容性问题 - 事实上,导致兼容性问题的是古老的xls。例如,除非您付费,否则 Google 表格不支持 xls 文件。 xls 坚持的唯一原因是惯性。

如果你坚持使用xls(为什么?)你可以使用ExcelDataReaader。该库可以读取xlsxlsx 文件并返回DbDataReaderDataSetNuGet package 的下载量为 1700 万次,使其成为继 EPPlus 之后第二受欢迎的 Excel 库。

存储库页面中的示例显示了如何在最简单的情况下使用它 - ExcelReaderFactory.CreateReader(stream) 返回 DbDataReader

using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read))
{
    // Auto-detect format, supports:
    //  - Binary Excel files (2.0-2003 format; *.xls)
    //  - OpenXml Excel files (2007 format; *.xlsx, *.xlsb)
    using (var reader = ExcelReaderFactory.CreateReader(stream))
    {
        // Choose one of either 1 or 2:

        // 1. Use the reader methods
        do
        {
            while (reader.Read())
            {
                // reader.GetDouble(0);
            }
        } while (reader.NextResult());

        // 2. Use the AsDataSet extension method
        var result = reader.AsDataSet();

        // The result of each spreadsheet is in result.Tables
    }
}

【讨论】:

  • 为什么投反对票??
  • @MarkPflug 是的,他会的。因为xls 已过时且任何 应用程序都不需要它,而它确实 会导致兼容性和驱动程序问题。所以使用xls 是一个非常糟糕的主意。
  • “xls 已过时”。这根本不是真的。 Excel 仍会打开并保存该格式,因此它不会过时,而且永远不会过时。
  • 您好,xls 不是我的主意,不幸的是,这是我坚持的,如果由我决定,我会通过程序或 API 直接获取数据,但我开始推回那里。该格式是由一方保存的,不会更改它,因为有很多旧的宏被写入使用相同的文件,并且代码写得不好,路径嵌入到它上面,即使我问了一个列表,所以我可以把它们搞定,没有人是能够提供帮助。不幸的是,在老牌大公司中,没有什么东西真的会死掉,比如 xls 格式......
  • 我还将测试 ExcelDataReader 和 Mark 回复中的一个,并测试解决方案速度和稳定性的速度,谢谢大家 :)
猜你喜欢
  • 2010-11-12
  • 2011-06-06
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 2018-01-10
  • 1970-01-01
  • 1970-01-01
  • 2011-09-09
相关资源
最近更新 更多