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

导出报表,将程序中的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交互太过频繁。所以减少两个进程之间的交互,才能缩短导出时间。

时间: 2024-10-19 17:52:13

C#向Excel传输数据——批量dataTable的相关文章

读取指定路径的Excel内容到DataTable中

1 /// <summary> 2 /// 读取指定路径的Excel内容到DataTable中 3 /// </summary> 4 /// <param name="path"></param> 5 /// <returns></returns> 6 public DataTable ImportToDataSet(string path) 7 { 8 string strConn = "Provide

【分享】通过Excel生成批量SQL语句,处理大量数据的好办法

我们经常会遇到这样的要求:用户给发过来一些数据,要我们直接给存放到数据库里面,有的是Insert,有的是Update等等,少量的数据我们可以采取最原始的办法,也就是在SQL里面用Insert into来实现,但是如果有几十条几百条甚至上千条数据的时候继续写单独的SQL语句的话那就惨了,其实有两种简单的方法: 第一,将Excel数据整理好了之后,通过SQL的导入功能直接导进数据库,但是得保证数据库字段和Excel的字段一致. 第二,通过Excel来生成对应的SQL语句,直接将SQL语句复制到分析器

服务器不装Excel读取Excel并转换DataTable

原来是用OleDb.4.0组件读取Excel,但是放到服务器后 傻了,服务器没装Excel ,而且领导说不可以装 没办法,只好自己重新找下代码 在CodeProject找到一个开源的dll,一阵欢喜啊,虽然是winform项目,但是主要是用他的类库所以提取一下后 自己研究后重新封装了一个类,运行 耶! 完美支持 需要Dome的同学下载后去研究下吧 地址:http://download.csdn.net/detail/jine515073/7266371 本人用 Excel 97-2003 工作表

.net excel 转换成datatable,创建文件夹

protected void Button9_Click(object sender, EventArgs e) { string path = ""; path = FileUpload3.PostedFile.FileName; if (path == "") { string jss = "<script language='javascript' type='text/javascript'> alert('先选择文件')</sc

excel如何批量删除图片

编辑-定位-定位条件-对象-确定-DELETE,即将全部图片都删除了: 发现全部被选中了. 直接Delete掉就可以了. excel如何批量删除图片

【c#操作office】--OleDbDataAdapter 与OleDbDataReader方式读取excel,并转换为datatable

OleDbDataAdapter方式: /// <summary> /// 读取excel的表格放到DataTable中 ---OleDbDataAdapter /// </summary> /// <param name="strSql"></param>        /// <param name="excelpath">excel路径</param> /// <returns>

Excel 2007 批量删除隐藏的文本框[转]

该方法取自百度知道,该朋友给出函数,我详细写一下方法. 打开有文本框的excel文件. 按 Alt+F11 打开编辑器. 将下面的函数复制进去: Sub deltxbox()Dim s As ShapeFor Each s In ActiveSheet.ShapesIf s.Type = msoTextBox Then s.DeleteNextEnd Sub 然后按 F5  执行即可! 转载:http://www.cnblogs.com/findw/p/3737343.html Excel 20

SqlServer表和excel数据批量复制方法

SqlServer表和excel数据批量复制方法 一.SqlServer表数据复制到excel方法: 1.新建查询,用sql语句把表数据读出来 2.然后,选择数据,右键"复制"(如果需要表字段名称,则点击连同标题复制) 3.在excel中直接粘贴就好了. 二.excel复制到SqlServer表数据方法1: 1.打开excel复制数据. 2.用编辑状态打开sql表 3.右键点击表最下面一行左侧的序号,选择粘贴(注意:excel的列一定要和sql表的列对应) 4.如果有自增,不要复制自增

java把excel数据批量导入到数据库

java把excel数据批量导入到数据库中,java导入excel数据代码如下 1.    public List<Choice> GetFromXls(String xlsname){ 2. 3.        List<Choice> choices = new ArrayList<Choice>(); 4.        Choice choice=null; 5.        try { 6.            java.io.File file=new