惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threat Research - Cisco Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
V
Vulnerabilities – Threatpost
GbyAI
GbyAI
P
Proofpoint News Feed
L
LINUX DO - 热门话题
P
Palo Alto Networks Blog
A
About on SuperTechFans
T
Tenable Blog
M
MIT News - Artificial intelligence
IT之家
IT之家
I
Intezer
D
DataBreaches.Net
爱范儿
爱范儿
T
Threatpost
C
CERT Recently Published Vulnerability Notes
云风的 BLOG
云风的 BLOG
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
K
Kaspersky official blog
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
Y
Y Combinator Blog
Cyberwarzone
Cyberwarzone
酷 壳 – CoolShell
酷 壳 – CoolShell
D
Darknet – Hacking Tools, Hacker News & Cyber Security
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
Spread Privacy
Spread Privacy
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
AWS News Blog
AWS News Blog
博客园 - 聂微东
C
Check Point Blog
S
Securelist
有赞技术团队
有赞技术团队
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
Last Week in AI
Last Week in AI
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
D
Docker
G
GRAHAM CLULEY
T
The Exploit Database - CXSecurity.com
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tailwind CSS Blog
L
Lohrmann on Cybersecurity
G
Google Developers Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
L
LangChain Blog

博客园 - Zeus

11月11日北京.NET俱乐部活动通告 选择DataTable中的唯一值(Distinct) DotNet入门介绍 从Reflector说起 [导入]小记 [导入]北京这几天总是雷暴天气,非常反常 [导入]天路 [导入]翻开一张尘封已久的帖子 [导入]大城小事 [导入]闲人逸事 [导入]Sigh [导入]生活带给我的真正快乐,是能够助人助己 [导入]HANNIBAL [导入]近期的事情 [导入]最近比较忙 [导入]李玉平 [导入]子非鱼 [导入]Plan2 2 tips
将Excel读入DateTable的问题,兼谈考虑复用的设计
Zeus · 2006-10-31 · via 博客园 - Zeus

有位兄弟写了将Excel读入DataTable的代码如下:

 1using System;
 2using System.Data;
 3using System.Configuration;
 4using System.Web;
 5using System.Web.Security;
 6using System.Web.UI;
 7using System.Web.UI.WebControls;
 8using System.Web.UI.WebControls.WebParts;
 9using System.Web.UI.HtmlControls;
10using System.IO;
11using System.Reflection;
12using System.Runtime.InteropServices;
13
14
15/// <summary>
16/// 将Excel读取到DataTable中
17/// <!-- ------------------------------------------------------ -->
18/// <!--            Copyright ×××××××××××            -->
19/// <!--            Author:×××××                           -->
20/// <!--            Date:×××××                             -->
21/// <!--            Copyright ×××××××××××            -->
22/// <!-- Please see ××××××××××× for terms of use.    -->
23/// <!-- ------------------------------------------------------ -->
24/// </summary>

25public class ExcelToDataTable
26{
27    public ExcelToDataTable()
28    {
29        //
30        // TODO: Add constructor logic here
31        //
32    }

33    /// <summary>
34    /// 将上传Excel文件的一个Sheet读取到DataTable 
35    /// 通过传入sheet名称读取
36    /// </summary>
37    /// <param name="ExcelPath">excel文件所在路径</param>
38    /// <param name="SheetName">工作表名</param>
39    /// <param name="Range">读取数据区域(矩形范围,如A1:H4等)</param>
40    /// <returns></returns>

41    public static DataTable ExcelToDTBySheetName(string ExcelPath, string SheetName, string Range)
42    {
43        System.Data.OleDb.OleDbConnection oconn = new System.Data.OleDb.OleDbConnection();
44        System.Data.OleDb.OleDbDataAdapter oda = new System.Data.OleDb.OleDbDataAdapter();
45        System.Data.OleDb.OleDbCommand ocmd = new System.Data.OleDb.OleDbCommand();
46        System.Data.DataSet ds = new DataSet();
47        oconn.ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0;" + "data source=" + ExcelPath + ";Extended Properties=\"Excel 8.0;HDR=1\"";
48        oda.SelectCommand = ocmd;
49        ocmd.Connection = oconn;
50        oconn.Open();
51        ocmd.CommandText = "select * from [" + SheetName + "$" + Range + "]";
52        oda.Fill(ds);
53        oconn.Close();
54        DataTable dt = ds.Tables[0];
55        return dt;
56    }

57    /// <summary>
58    /// 将上传Excel文件的一个Sheet读取到DataTable 
59    /// 通过传入sheet序号读取,起始序号为0
60    /// </summary>
61    /// <param name="ExcelPath">excel文件所在路径</param>
62    /// <param name="SheetName">工作表名</param>
63    /// <param name="Range">读取数据区域(矩形范围,如A1:H4等)</param>
64    /// <returns></returns>

65    public static DataTable ExcelToDTBySheetIndex(string ExcelPath, int SheetIndex, string Range)
66    {
67        System.Data.OleDb.OleDbConnection oconn = new System.Data.OleDb.OleDbConnection();
68        System.Data.OleDb.OleDbDataAdapter oda = new System.Data.OleDb.OleDbDataAdapter();
69        System.Data.OleDb.OleDbCommand ocmd = new System.Data.OleDb.OleDbCommand();
70        System.Data.DataSet ds = new DataSet();
71        oconn.ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0;" + "data source=" + ExcelPath + ";Extended Properties=\"Excel 8.0;HDR=1\"";
72        oda.SelectCommand = ocmd;
73        ocmd.Connection = oconn;
74        oconn.Open();
75        DataTable schematable = oconn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);
76        string SheetName = schematable.Rows[SheetIndex][2].ToString().Trim();
77        ocmd.CommandText = "select * from [" + SheetName + Range + "]";
78        oda.Fill(ds);
79        oconn.Close();
80        DataTable dt = ds.Tables[0];
81        return dt;
82    }

83}

84

这位兄弟遇到的问题是读取出来的数据如果一列中既有数字又有字符读取结果会统一按照数字对待或按照字符对待,错误格式化为与原Excel不相同的数据。于是他强制编码啊,设定文化啊什么的折腾了一下午也没有变化,遂来问我,告诉他解决方法后该兄弟很吃惊兼郁闷,愤愤不平为什么有这样的参数。因为我改的地方只有一处:
将连接字符串的Extended Properties=\"Excel 8.0;HDR=1\"改为Extended Properties=\"Excel 8.0;HDR=1;IMEX=1\",指定IMEX=1将所有读入数据看作字符,否则出现数字/汉字同列不相容等现象,正如指定HDR=yes或no可以选择第一列是否当标题看待一样。可惜HDR的指定网络上说明较多而IMEX的说明网上较少。下面是将Excel读入DataTable的修改后代码:

 1using System;
 2using System.Data;
 3using System.Configuration;
 4using System.Web;
 5using System.Web.Security;
 6using System.Web.UI;
 7using System.Web.UI.WebControls;
 8using System.Web.UI.WebControls.WebParts;
 9using System.Web.UI.HtmlControls;
10using System.IO;
11using System.Reflection;
12using System.Runtime.InteropServices;
13
14
15/// <summary>
16/// 将Excel读取到DataTable中
17/// <!-- ------------------------------------------------------ -->
18/// <!--            Copyright ×××××××××××            -->
19/// <!--            Author:×××××                           -->
20/// <!--            Date:×××××                             -->
21/// <!--            Copyright ×××××××××××            -->
22/// <!-- Please see ××××××××××× for terms of use.    -->
23/// <!-- ------------------------------------------------------ -->
24/// </summary>

25public class ExcelToDataTable
26{
27    public ExcelToDataTable()
28    {
29        //
30        // TODO: Add constructor logic here
31        //
32    }

33    /// <summary>
34    /// 将上传Excel文件的一个Sheet读取到DataTable 
35    /// 通过传入sheet名称读取
36    /// </summary>
37    /// <param name="ExcelPath">excel文件所在路径</param>
38    /// <param name="SheetName">工作表名</param>
39    /// <param name="Range">读取数据区域(矩形范围,如A1:H4等)</param>
40    /// <returns></returns>

41    public static DataTable ExcelToDTBySheetName(string ExcelPath, string SheetName, string Range)
42    {
43        System.Data.OleDb.OleDbConnection oconn = new System.Data.OleDb.OleDbConnection();
44        System.Data.OleDb.OleDbDataAdapter oda = new System.Data.OleDb.OleDbDataAdapter();
45        System.Data.OleDb.OleDbCommand ocmd = new System.Data.OleDb.OleDbCommand();
46        System.Data.DataSet ds = new DataSet();
47        oconn.ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0;" + "data source=" + ExcelPath + ";Extended Properties=\"Excel 8.0;HDR=1;IMEX=1\"";
48        oda.SelectCommand = ocmd;
49        ocmd.Connection = oconn;
50        oconn.Open();
51        ocmd.CommandText = "select * from [" + SheetName + "$" + Range + "]";
52        oda.Fill(ds);
53        oconn.Close();
54        DataTable dt = ds.Tables[0];
55        return dt;
56    }

57    /// <summary>
58    /// 将上传Excel文件的一个Sheet读取到DataTable 
59    /// 通过传入sheet序号读取,起始序号为0
60    /// </summary>
61    /// <param name="ExcelPath">excel文件所在路径</param>
62    /// <param name="SheetName">工作表名</param>
63    /// <param name="Range">读取数据区域(矩形范围,如A1:H4等)</param>
64    /// <returns></returns>

65    public static DataTable ExcelToDTBySheetIndex(string ExcelPath, int SheetIndex, string Range)
66    {
67        System.Data.OleDb.OleDbConnection oconn = new System.Data.OleDb.OleDbConnection();
68        System.Data.OleDb.OleDbDataAdapter oda = new System.Data.OleDb.OleDbDataAdapter();
69        System.Data.OleDb.OleDbCommand ocmd = new System.Data.OleDb.OleDbCommand();
70        System.Data.DataSet ds = new DataSet();
71        oconn.ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0;" + "data source=" + ExcelPath + ";Extended Properties=\"Excel 8.0;HDR=1;IMEX=1\"";
72        oda.SelectCommand = ocmd;
73        ocmd.Connection = oconn;
74        oconn.Open();
75        DataTable schematable = oconn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);
76        string SheetName = schematable.Rows[SheetIndex][2].ToString().Trim();
77        ocmd.CommandText = "select * from [" + SheetName + Range + "]";
78        oda.Fill(ds);
79        oconn.Close();
80        DataTable dt = ds.Tables[0];
81        return dt;
82    }

83}

84

其实这并不是一个好设计,就像结构化异常处理出来之前用错误号返回错误一样,需要什么查询说明甚至猜测尝试来得到解决之道,除了能让知道的人沾沾自喜、成为不知者的编程障碍外没有多大作用。应该在设计方法时需要避免这种情况发生,以有意义的参数或明确的参数说明帮助使用者在最短时间内掌握正确的方法使用之道。

Excel导到DataTable,问题本身很简单,但折射出很多需要思考的东西。编码层级的设计模式并不能解决所有的问题,我们写每个方法的时候,可曾细细考虑过自己的方法在别人复用时有无人为的障碍?如何才能减少自己的方法、模块、程序集复用的人为障碍?