3

'正在使用 Microsoft.ACE.OLEDB.12.0 提供程序从 Excel 表中读取数据。我正在使用OleDbDataReader和他GetValue()的来获取数据。第一行/行(可以多于一个)是字符串标题,我不能跳过它。接下来是设置为 0 小数位的数字数据,但是当我选择其中一个时,它会以正确的十进制格式显示在栏中。

如何以完整的原始十进制格式读取这些混合数据,如 Excel 中的栏?我无法更改 Excel 工作表的设置。

在此处输入图像描述

这是我的代码:

using System.Data.OleDb;

    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                string query = "SELECT * FROM [List1$]";
                string connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\Temp\Test.xls;Extended Properties=""Excel 12.0;HDR=NO;IMEX=1""";
                using (OleDbConnection connection = new OleDbConnection(connString))
                {
                    connection.Open();
                    using (OleDbCommand command = new OleDbCommand(query, connection))
                    {
                        using (OleDbDataReader reader = command.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                object value = reader.GetValue(0);
                            }
                        }
                    }
                }
            }
        }
    }
4

2 回答 2

2

尝试HDR=YES在您的连接字符串中使用并停止跳过第一行:

string connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\Temp\Test.xls;Extended Properties=""Excel 12.0;HDR=YES;IMEX=1""";

[更新]

我建议您使用的解决方法是读取两次文件(使用相同的方法):

  1. 首先,你得到了标题行,可能你稍后会需要它作为数据结构
  2. 在第二次阅读时,您跳过标题并阅读行。

它应该是这样的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.OleDb;
using System.Data;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        // the Excel file
        string file = @"c:\Temp\Test.xls";

        if (!File.Exists(file))
        {
            Console.WriteLine("File not found.");
            return;
        }

        // DataTable bonus! :)
        System.Data.DataTable dt = new System.Data.DataTable();

        IEnumerable<List<object>> header = new List<List<object>>();
        IEnumerable<List<object>> rows = new List<List<object>>();

        // read the header first
        header = GetData(file, true);

        // read the rows
        rows = GetData(file, false);

        // add the columns
        foreach (var column in header.First())
        {
            dt.Columns.Add(column.ToString());
        }

        // add the rows
        foreach (var row in rows)
        {
            dt.Rows.Add(row.ToArray());
        }

        // now you may use the dt DataTable for your purpose
    }

    /// <summary>
    /// Read from the Excel file
    /// </summary>
    /// <param name="file">The path to the Excel file</param>
    /// <param name="readHeader">True if you want to read the header, 
    /// False if you want to read the rows</param>
    /// <returns></returns>
    private static IEnumerable<List<object>> GetData(string file, bool readHeader)
    {
        string query = "SELECT * FROM [List1$]";
        string connString = @"Provider=Microsoft.ACE.OLEDB.12.0;" +
            @"Data Source=" + file + @";Extended Properties=""Excel 12.0 Xml;HDR=NO;IMEX="
            + ((readHeader) ? "1" : "0") + @";""";
        using (OleDbConnection connection = new OleDbConnection(connString))
        {
            connection.Open();
            using (OleDbCommand command = new OleDbCommand(query, connection))
            {
                using (OleDbDataReader reader = command.ExecuteReader())
                {
                    bool isHeaderRead = false;
                    while (reader.Read())
                    {
                        if (readHeader && isHeaderRead)
                        { break; }
                        isHeaderRead = true;
                        List<object> values = new List<object>();
                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            values.Add(reader.GetValue(i));
                        }
                        yield return values;
                    }
                }
            }
        }
    }
}
于 2013-02-22T14:02:12.887 回答
2

根据经验,您可能会做的最好的事情就是以下。我一直对excel文件有问题,读取数据。这就是为什么我鄙视excel作为数据传输机制的原因。

我在一家通过 excel 获取所有“银行数据”的公司工作。我很高兴被证明是错误的。

笔记。GetValue(0) 运行后,请对其进行监视。它可能会告诉你它是一个字符串。但是你可以确定它认为它是什么,然后稍微调整你的“获取”方法。就像,如果值是“字符串”,您可以将 GetValue(0) 更改为 GetString(0)。

while (reader.Read())
{
    Decimal tryParseResultDec;
    object value = reader.GetValue(0);
    if !(Decimal.TryParse(value, out tryParseResultDec))
    {
        throw new ArgumentException(string.Format("Unable to parse '{0}'.", value));   
    }

}

额外的建议。

我通常在类的顶部放置一些私有常量,而不是“0”、“1”、“2”等,以告诉我这些列是什么。

private const int EXCEL_COLUMN_TOTAL_AMOUNT = 0;

(你可以做类似的事情,你只是保持简单的例子)

额外提示:

我认为它的工作方式是 excel 将查看第一行数据,查看数据类型,并将其用于同一列中的其余行。我不认为它说“检查每一行的数据类型”。因此你的难题。

如果您说没有标题行,它将在 A1 中查找 A 中所有行的数据类型。如果您说有标题行,它将在 A2 中查找 A 中所有行的数据类型。

于 2013-02-22T14:45:32.280 回答