C#:从 32 位切换到 64 位后需要 XLS 库

C#: XLS library needed after switching from 32BIT to 64BIT

原始查询: 目前我想从 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]";

安装64位OLE驱动不在话下。所以也许有人偶然发现了它,或者有任何想法。

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

此外,由于 excel 格式,短小精悍是不可能的:(

我试图找到一些问题,但我能找到的只是为 64 位安装 OLEDB Driver。

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

他还指出 .xls 很古老,但不幸的是它并没有过时,因为我公司的许多流程仍然依赖它。但它应该是 osbsolete,不幸的是,我们由于计划不周的流程而陷入困境,而不是因为 .xls 有用。尤其是那些公司应该看看某些格式不受支持的事实,或者可能会失去这种支持,因为 .xls 正在慢慢获得这种待遇。

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

最后编辑:

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

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

**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]: 
  [2]: https://github.com/MarkPflug/Sylvan.Data.Excel

您可以查看我的图书馆 Sylvan.Data.Excel. It has no external dependencies, is cross plat, open-source, MIT licensed, and also the fastest Excel data reader for .NET。它通过相同的 API 同时支持 .xls、.xlsx 和 .xlsb。它不像其他一些库那样功能齐全,它只支持读取(不支持写入),但它应该是 ACE 的一个相当直接的替代品,因为它实现了 DbDataReader。如果您 运行 进入任何 issues/questions,请随时在 GitHub 存储库中打开它们。

使用起来非常简单:


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

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

默认情况下,它会期望每个 sheet 的第一行包含 headers。然而,这可以被禁用。禁用时,只能按顺序访问列。

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

由于它实现了DbDataReader,将其加载到数据table中是一个one-liner:

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

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

如果您坚持使用 xls(为什么?)您可以使用 ExcelDataReaader. That library can read both xls and xlsx files and return either an DbDataReader or a DataSet. The NuGet package 有 17M 的下载量,使其成为继 EPPlus 之后第二受欢迎的 Excel 库。

存储库页面中的示例显示了如何在最简单的情况下使用它 - ExcelReaderFactory.CreateReader(stream) returns a 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
    }
}