码迷,mamicode.com
首页 > Windows程序 > 详细

C#向Excel传输数据——批量dataTable

时间:2015-05-23 11:33:15      阅读:275      评论:0      收藏:0      [点我收藏+]

标签:

    导出报表,将程序中的list或者dataTable进行组织。然后通过特定的形式,显示到Excel或者word中,方便打印。

 

   目前正在使用的方式,事先用报表设计工具,设置一个模板,然后导出报表的时候,读取模板,然后将模板中的数据进行替换。这也是最常用的一个方式。

 

   我们公司,现在没有使用报表工具,使用的Excel。

   使用Excel做报表模板,然后向Excel中写数据,进而达到一个导出报表的功能。

   因为有大量的数据需要写入到Excel,标签只是一个标记。

 

这样就提供了两种写入Excel的方式:

 

方法一

    逐个单元格进行数据传输。程序和Excel相互交互

方法二

    将大量有规律的数据,直接传输给Excel,标签只是一个起始位置。程序和Excel交互一次。

 

测试两种方法时间比较

    在6000条数据的测试下,

    第一种方案,2min54s

    第二种方案,1min22s

 

    很显然,直接把dataTable提交给Excel比一个一个的写单元格要快的多。节省的时间,就是程序和Excel进行数据交互的过程。

 

导出模板设计思路:

    1、写一个Excel模板,在里面写一些标签

    2、替换模板中的标签,然后向里面写数据

    3、对报表中的数据区域进行格式调整

 

模板中的行数不固定,列数不固定,所以模板大概形式如下:

 

技术分享

然后,把数据,替换到标签中。

 

在使用第一种方案的时候,导出花费的时间 都在第二步  替换{T$data} 标签上。时间复杂度 O(n2)

 

所以在导出的数据量过大的时候,慢就算了。而且,这种方案还会报错。

 

   “如果您具有少量的数据,则逐个单元格地传输数据是可以接受的方法。您可以灵活地将数据放到工作簿中的任何地方,并可以在运行时根据条件对单元格进行格式设置。然而,如果您具有大量需要传输到 Excel 工作簿的数据,则使用这种方法不是一个好主意。您在运行时获取的每一个Range 对象都会产生一个接口请求,这意味着数据传输速度会变得较慢。此外,Microsoft Windows 95、Microsoft Windows 98 以及 Microsoft Windows Millennium Edition (Me) 都对接口请求有 64 KB 的限制。如果您具有 64 KB 以上的接口请求,则“自动化”服务器 (Excel) 可能会停止响应,或者您可能会收到指出内存不足的错误信息。”

 

//读取Excel模板并打开
string execPath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
pathTemplateFile = Path.Combine(Path.Combine(execPath, @"File\"), "Template.xlt");

var myExcel = new Excel.Application
{
Visible = true,
UserControl = true,
DisplayAlerts = false,
AlertBeforeOverwriting = false
};

Excel.Workbooks workbooks = myExcel.Workbooks;
Excel._Workbook workbook = workbooks.Add(pathTemplateFile);
Excel.Sheets sheets = workbook.Sheets;


 

第一种方案的实现:

 

代码实现:

((Excel.Range)worksheet.Rows[rng.Row, missing]).Copy(worksheet.Rows[curRow, missing]);
foreach (DataRow dr in tableData.Rows)
{
// 插入行并复制格式行                            rng.EntireRow.Insert(Excel.XlInsertShiftDirection.xlShiftDown);
   //((Excel.Range)worksheet.Rows[rng.Row, missing]).Copy(worksheet.Rows[curRow, missing]);

    // 填充行数据
    var curCol = rng.Column;
    foreach (DataColumn dc in tableData.Columns)
    {
    	worksheet.Cells[curRow, curCol] = dr[dc].ToString();
       curCol++;
     }
     curRow++;
}


 

第二种方案:

   使用Range对象的CopyfromRecordset方法,直接将dataTable放入到标签的位置(标签作为左上角的单元格)

//复制{$Cols}所在行的格式
((Excel.Range)worksheet.Rows[rng.Row, missing]).Copy(worksheet.Rows[curRow, missing]);                        for (int j = 0; j < dbRows; j++)
{
//然后以dataTable 的行数 插入若干行           rng.EntireRow.Insert(Excel.XlInsertShiftDirection.xlShiftDown);
}

//寻找标签
object findText = "{T$data}";
//获取标签所在位置的Range
Excel.Range objRange = worksheet.Rows.Find(find, missing, missing, missing, missing, Excel.XlSearchDirection.xlNext, missing, missing);//获取Range对象 

//使用该Range对象,把数据集 直接放到标签的位置
objRange.CopyFromRecordset(rs, Type.Missing, Type.Missing);


 

其中,rs是ADODB.Recordset对象。

//将数据区域的dataTable转换成Recordset
ADODB.Recordset rs = ConvertToRecordset(dtTable); 
//获取数据区域的行数
int dbRows = dtTable.Rows.Count;
//获取数据区域的列数
int dbCols = dtTable.Columns.Count;


 

   注意CopyFromRecordset 只能与 ADORecordset 对象一起使用。使用 ADO.NET 创建的DataSet 不能与 CopyFromRecordset 方法一起使用。以下几部分中的多个示例演示了如何利用 ADO.NET 向 Excel 传输数据。

 

所以需要将dataTable转换为Recordset对象。

/// <summary>
/// 将Datatable转换成Recordset对象
/// </summary>
/// <param name="inTable"></param>
/// <returns></returns>
public static  ADODB.Recordset ConvertToRecordset(DataTable inTable)
{
    ADODB.Recordset result = new ADODB.Recordset();
    result.CursorLocation = ADODB.CursorLocationEnum.adUseClient;

    ADODB.Fields resultFields = result.Fields;
    System.Data.DataColumnCollection inColumns = inTable.Columns;

    foreach (DataColumn inColumn in inColumns)
    {
        resultFields.Append(inColumn.ColumnName
            //, TranslateType(inColumn.DataType)
            , TranslateType(inColumn.DataType)
            , inColumn.MaxLength
            , inColumn.AllowDBNull ? ADODB.FieldAttributeEnum.adFldIsNullable :
                                     ADODB.FieldAttributeEnum.adFldUnspecified
            , null);
    }

    result.Open(System.Reflection.Missing.Value
            , System.Reflection.Missing.Value
            , ADODB.CursorTypeEnum.adOpenStatic
            , ADODB.LockTypeEnum.adLockOptimistic, 0);

    foreach (DataRow dr in inTable.Rows)
    {
        result.AddNew(System.Reflection.Missing.Value,
                      System.Reflection.Missing.Value);

        for (int columnIndex = 0; columnIndex < inColumns.Count; columnIndex++)
        {
            resultFields[columnIndex].Value = dr[columnIndex];
        }
    }

    return result;
}

static ADODB.DataTypeEnum TranslateType(Type columnType)
{
    switch (columnType.UnderlyingSystemType.ToString())
    {
        case "System.Boolean":
            return ADODB.DataTypeEnum.adBoolean;

        case "System.Byte":
            return ADODB.DataTypeEnum.adUnsignedTinyInt;

        case "System.Char":
            return ADODB.DataTypeEnum.adChar;

        case "System.DateTime":
            return ADODB.DataTypeEnum.adDate;

        case "System.Decimal":
            return ADODB.DataTypeEnum.adCurrency;

        case "System.Double":
            return ADODB.DataTypeEnum.adDouble;

        case "System.Int16":
            return ADODB.DataTypeEnum.adSmallInt;

        case "System.Int32":
            return ADODB.DataTypeEnum.adInteger;

        case "System.Int64":
            return ADODB.DataTypeEnum.adBigInt;

        case "System.SByte":
            return ADODB.DataTypeEnum.adTinyInt;

        case "System.Single":
            return ADODB.DataTypeEnum.adSingle;

        case "System.UInt16":
            return ADODB.DataTypeEnum.adUnsignedSmallInt;

        case "System.UInt32":
            return ADODB.DataTypeEnum.adUnsignedInt;

        case "System.UInt64":
            return ADODB.DataTypeEnum.adUnsignedBigInt;

        case "System.String":
        default:
            return ADODB.DataTypeEnum.adVarChar;
    }
}


   在以上两种方法中,第一种方法,写入数据慢,原因就是程序与Excel交互太过频繁。所以减少两个进程之间的交互,才能缩短导出时间。

 

C#向Excel传输数据——批量dataTable

标签:

原文地址:http://blog.csdn.net/zc474235918/article/details/45932437

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!