2013-02-22 22 views
3

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

如何读取像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); 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
+0

您是否尝试使用“.GetDecimal”而不是“.GetValue”? – jbl 2013-02-22 13:44:49

+0

是的。 GetDecimal抛出异常,因为有空格字符。 GetFieldType返回字符串。所以它必须在OleDbCommand或OleDbConnection设置的某个地方,也许在连接字符串中有一些attribut。 – Ciboor 2013-02-22 13:55:41

+0

我编辑了你的标题。请参阅:“[应该在其标题中包含”标签“](http://meta.stackexchange.com/questions/19190/)”,其中的共识是“不,他们不应该”。 – 2013-02-22 15:08:58

回答

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

谢谢你对这些例子的工作,不幸的是我不能通过使用HDR = YES来禁用头。 – Ciboor 2013-02-22 14:10:50

+0

对不起,我错误地提出了这个问题。 – Ciboor 2013-02-22 14:35:04

+0

@Ciboor,现在怎么样? – 2013-02-22 15:21:03

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; 

(你可以做这样的事情,你只是不停的例子简单)

EXTRA提示:

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

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

+0

谢谢你的帮助。如果GetValue()返回正确的数据,但它返回没有小数位数的数据。关于小数的信息丢失。 – Ciboor 2013-02-22 15:01:50

+0

好吧,我现在看到。该专栏有数据类型的大杂烩。是啊。 “格式化”设置将会导致你的错误。我们必须和客户讨论这个问题。首先,我们有一条规则,即每一列在数据类型上必须保持一致。他们有2行“一条记录”的数据。就像在第1行colA中,会有“LastName”,而在第2行colA中,会有“TransactionAmount”...(第1行和第2行创建了一个“记录”)所以我们必须让它们或者(1)一个excel行或(2)row1 colA上的数据具有LastName,而row2 colB具有TAmount,但row1 colB或row2 colA中没有数据。 – granadaCoder 2013-02-22 15:10:20

+0

所以格式化是个别金额的四舍五入,有时聚合数据将被关闭1便士。我们必须编写一个规则来说“允许1便士”......因为excel是如何进行四舍五入的。因此.........为什么我讨厌excel作为数据传输机制。 – granadaCoder 2013-02-22 15:15:33

相关问题