当第一行是字符串时,GetValue()不读取十进制值

时间:2013-02-22 13:37:32

标签: c# sql-server excel c#-3.0 oledb

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

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

enter image description here

这是我的代码:

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);
                            }
                        }
                    }
                }
            }
        }
    }

2 个答案:

答案 0 :(得分: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""";

<强> [UPDATE]

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

  1. 首先,您获得标题行,可能稍后需要为数据结构
  2. 在第二次阅读时,您跳过标题并阅读行。
  3. 以下是它的外观:

    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;
                        }
                    }
                }
            }
        }
    }
    

答案 1 :(得分: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”等,我通常会在类的顶部放置一些私有const来告诉我列是什么。

private const int EXCEL_COLUMN_TOTAL_AMOUNT = 0;

(你可以这样做,你只是保持这个例子简单)

额外提示:

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

如果你说没有标题行,它会在A1中查看A中所有行的数据类型。如果你说有一个标题行,它将在A2中查看A中所有行的数据类型。