Exemplo de uso – Manipulando Planilhas Excel com ADO.NET
Leonel Fraga de Oliveira 14/02/2009 00:00

Agora sim, finalmente temos a conclusão de dois artigos (este e este outro :-) ) que tratam de como manipular, seja lendo ou escrevendo uma planilha do Excel fazendo o uso das classes do ADO.NET e do provider OleDB.

Nos artigos mencionados, foram apresentados dois métodos: um para fazer a leitura de uma planilha e jogar em um DataTable e outro para varrer um DataTable e criar uma nova planilha a partir dele.

Agora, vamos criar uma aplicação ASP.NET na qual o usuário tem na tela um gridview com o resultado de um DataTable e um botão para exportar este grid para uma planilha e outro botão que permitirá fazer o upload de uma planilha e ter seus dados listados no grid.

No Visual Studio, crie um website habilitado para AJAX, coloque os arquivos de suporte necessários (no nosso exemplo, o jQuery, o jqModal, e imagens) e crie uma classe (na pasta App_Code) chamada Auxiliar. Depois iremos fazer o design da página.

Coloque o seguinte código na classe Auxiliar:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.OleDb;
using System.IO;

/// 
/// Classe auxiliar do Exemplo de Importação/Exportação Excel -> DataTable via ADO.NET
/// 
public class Auxiliar
{
	public Auxiliar()
	{
		//
		// TODO: Add constructor logic here
		//
	}

    public DataTable CreateSampleTable()
    {
        //Estrutura
        DataTable dt = new DataTable();
        dt.TableName = "ExemploDataTable2Excel";
        dt.Columns.Add(new DataColumn("CODIGO"));
        dt.Columns.Add(new DataColumn("NOME"));
        dt.Columns.Add(new DataColumn("SEXO"));
        dt.Columns.Add(new DataColumn("PROFISSAO"));

        
        //Dados Exemplo
        dt.Rows.Add(1, "CLODOVIL HERNANDES", "G", "DE*PUTA*DO ESTADUAL" );
        dt.Rows.Add(2, "JUCA KIFOURI", "M", "JORNALISTA");
        dt.Rows.Add(3, "BENJAMIN 'NARIGUDO' BACK", "M", "APRESENTADOR DO ESTÁDIO 97" );
        dt.Rows.Add(4, "MILLY LACOMBE", "L", "REPÓRTER MALA" );
        dt.Rows.Add(5, "ROGÉRIO CENI", "M", "GOLEIRO DO TRICOLAÇO DO MORUMBI" );
        dt.Rows.Add(6, "MICHELE", "F", "DELÍCIA DO BBB 9 (ops... MODELO)" );
        dt.Rows.Add(6, "MARIA DAS GRAÇAS MENEGHEL", "B", "ATRIZ DE FILME EDUCATIVO");
        dt.Rows.Add(6, "ALEXANDRE FROTA", "B", "ATOR DE FILME EDUCATIVO");
        dt.Rows.Add(6, "GALVÃO BUENO", "M", "LOCUTOR MALA DA REDE BOBO");

        return dt;
    }

    /// 
    /// Importa os dados de uma planilha Excel para um datatable
    /// 
    /// Caminho do arquivo xls
    /// Nome da planilha a ser importada.
    /// 
    public DataTable ExcelPlan2DataTable(string pWorksheetPath, string pPlanName)
    {
        string cnnString = String.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=""Excel 8.0;HDR=YES;""", pWorksheetPath);
        string isql = "select * from [{0}$]";
        System.Data.OleDb.OleDbConnection cnn = new System.Data.OleDb.OleDbConnection(cnnString);
        System.Data.OleDb.OleDbDataAdapter da = new System.Data.OleDb.OleDbDataAdapter(String.Format(isql, pPlanName), cnn);
        DataSet ds = new DataSet();
        DataTable dt = new DataTable();
        try
        {
            cnn.Open();
            da.Fill(ds);
            dt = ds.Tables[0];
        }
        finally
        {
            cnn.Close();
            cnn.Dispose();
            da.Dispose();
            ds.Dispose();
        }
        return dt;
    }

    /// 
    /// Exporta um DataTable para uma Planilha Excel
    /// 
    /// Caminho da Planilha Base
    /// Caminho da Planilha a ser salva (temporária)
    /// Datatable a ser exportado
    /// Nome da planilha de destino
    /// String de Ordenação (DataView)
    /// Array de bytes com a planilha no formato Microsoft Excel.
    /// A planilha de destino deverá ter OS MESMOS CAMPOS do datatable de origem.
    public byte[] DataTable2ExcelPlan(string pBaseWorksheetPath, string pTempWorksheetPath, DataTable pDtOrigem, string pOrdenar)
    {
        //Copia a planilha de origem
        File.Copy(pBaseWorksheetPath, pTempWorksheetPath, true);
        //Fim da rotina de cópia

        //Instancia planilha de destino, criando um DataTable para inserir os dados
        string cnnString = String.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=""Excel 8.0;HDR=YES;""", pTempWorksheetPath);
        string sqlInsertGen = "insert into [{0}$] ({1}) values ({2})";

        System.Data.OleDb.OleDbConnection cnn = new System.Data.OleDb.OleDbConnection(cnnString);
        System.Data.OleDb.OleDbCommand cd = new System.Data.OleDb.OleDbCommand();
        cd.Connection = cnn;

        //Cria uma nova planilha no Excel

        //Cria nova planilha e Monta SQL de inserção
        string cmdCreateTable = "create table {0} ({1})";
        string Campos = "";
        string Values = "";
        string CamposCreate = "";
        int contador = 0;
        foreach (DataColumn dc in pDtOrigem.Columns)
        {
            Campos += dc.ColumnName + ",";
            Values += ""{" + contador.ToString() + "}",";
            CamposCreate += dc.ColumnName + " varchar(30),";
            contador++;
        }

        Campos = Campos.Substring(0, Campos.Length - 1);
        Values = Values.Substring(0, Values.Length - 1);
        CamposCreate = CamposCreate.Substring(0, CamposCreate.Length - 1);
        string sqlInsert = String.Format(sqlInsertGen, pDtOrigem.TableName, Campos, Values);

        //Fim da montagem do SQL de inserção

        try
        {
            cnn.Open();
            cd.CommandText = String.Format(cmdCreateTable, pDtOrigem.TableName, CamposCreate);
            cd.ExecuteNonQuery();

            if (!pOrdenar.Equals(""))
            {
                DataView dv = pDtOrigem.DefaultView;
                dv.Sort = pOrdenar;
                pDtOrigem = dv.ToTable();
            }

            //Cópia dos dados
            foreach (DataRow rOrigem in pDtOrigem.Rows)
            {
                object[] valores = new object[pDtOrigem.Columns.Count];
                int ctValores = 0;
                foreach (DataColumn cOrigem in pDtOrigem.Columns)
                {
                    valores[ctValores] = rOrigem[cOrigem.ColumnName].ToString();
                    ctValores++;
                }
                cd.CommandText = String.Format(sqlInsert, valores);
                cd.ExecuteNonQuery();
            }
        }
        finally
        {
            cnn.Close();
            cnn.Dispose();
            cd.Dispose();
        }
        //Fim da inserção dos dados na planilha

        //Captura a planilha de destino para um stream e saída no array de bytes
        FileStream fs = new FileStream(pTempWorksheetPath, FileMode.Open);
        byte[] planOutput = new byte[fs.Length];

        try
        {
            fs.Position = 0;
            fs.Read(planOutput, 0, (int)fs.Length);
        }
        finally
        {
            fs.Close();
            fs.Dispose();
            File.Delete(pTempWorksheetPath);
        }
        //Fim da captura do arquivo final
        return planOutput;
    }
}

Como você pode ver, ela possui os dois métodos de manipulação de planilha já explicados nos outros artigos e um que cria um DataTable de exemplo.

Agora vamos trabalhar o site em si.

Coloque o arquivo uploadFIle.aspx e seu respectivo código (você pode encontrá-lo aqui) no projeto e faça as adaptações necessárias (dependendo do tipo de projeto, algumas modificações na diretiva Page e a classe do code-behind não tem namespace). Em seguida, coloque o seguinte código na página Default.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Exemplo Importação Planilha Excel para DataTable</title>
    <link type="text/css" rel="stylesheet" href="css/jqModal.css" />

    <script type="text/javascript" src="javascript/jquery-1.2.6.pack.js"></script>

    <script type="text/javascript" src="javascript/jqModal.js"></script>
    
    <style type="text/css">
        .oculto {visibility:hidden;}
    </style>

</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <div id="Principal">
            <div style="width: 100%; text-align: center">
                <span>Exemplo de Importação de Planilha Excel para DataTable</span></div>
            <asp:UpdatePanel runat="server" ID="Upd1">
                <Triggers>
                    <asp:PostBackTrigger ControlID="btnExportar" />
                </Triggers>
                <ContentTemplate>
                    <div style="width: 100%; text-align: center">
                        <asp:Button runat="server" ID="btnImportar" Text="Importar Planilha" OnClientClick="$dvUpload.jqmShow();return false;" />
                        <asp:Button runat="server" ID="btnExportar" Text="Exportar Dados do Grid" OnClick="btnExportar_Click" />
                        <input type="button" id="btnSinalizaUpload" style="visibility:hidden" onclick='<%=btnProcessar.ClientID + ".click();"%>' />
                        <asp:Button runat="server" ID="btnProcessar" CssClass="oculto" OnClick="btnProcessar_Click" />
                    </div>
                    <br />
                    <asp:GridView runat="server" ID="gvDados" AutoGenerateColumns="false" Width="100%">
                        <HeaderStyle BackColor="red" Font-Names="Verdana" HorizontalAlign="Center" ForeColor="black"
                            Font-Bold="true" />
                        <RowStyle BackColor="beige" Font-Names="Verdana" />
                        <Columns>
                            <asp:BoundField DataField="CODIGO" HeaderText="Código" />
                            <asp:BoundField DataField="NOME" HeaderText="Nome" />
                            <asp:BoundField DataField="SEXO" HeaderText="Sexo" />
                            <asp:BoundField DataField="PROFISSAO" HeaderText="Profissão" />
                        </Columns>
                    </asp:GridView>
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
        <div id="dvUpload" class="jqmWindow">
            <div style="width: 100%; text-align: center">
                <span>Selecione o Arquivo Excel para importação</span></div>
                <iframe src="uploadFile.aspx" style="border:none 0px white;width:400px;height:80px;"></iframe>
            <div style="text-align: center; width: 100%;">
                <input type="button" value="Fechar esta janela" onclick="$dvUpload.jqmHide();return false;" />
            </div>
        </div>

        <script type="text/javascript">
                //Inicializa o Modal
                var $dvUpload = $('#dvUpload').jqm({modal:true,toTop:true,trigger:false});
        </script>

    </form>
</body>
</html>

E também o code-behind:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        { 
            Auxiliar au = new Auxiliar();
            gvDados.DataSource = au.CreateSampleTable();
            gvDados.DataBind();
        }
    }

    protected void btnProcessar_Click(object sender, EventArgs e)
    {
        if (Session["AREA_UPLOAD"] != null)
        {
            Auxiliar au = new Auxiliar();
            string Path = Server.MapPath(this.AppRelativeVirtualPath);
            FileInfo fi = new FileInfo(Path);
            string PlanPath = fi.Directory + "plantempimp" + Session.SessionID + ".xls";
            try
            {
                FileStream fs = new FileStream(PlanPath, FileMode.Create);
                fs.Write((byte[])Session["AREA_UPLOAD"], 0, (Session["AREA_UPLOAD"] as byte[]).Length);
                fs.Close();
                gvDados.DataSource = au.ExcelPlan2DataTable(PlanPath, "ExemploExcel2DataTable");
                gvDados.DataBind();
            }
            finally
            {
                File.Delete(PlanPath);
                Session.Remove("AREA_UPLOAD");
            }
        }
        
        ScriptManager.RegisterStartupScript(this, this.GetType(), "teste", "alert('caralho com asa fumegante e voador');", true);
    }

    protected void btnExportar_Click(object sender, EventArgs e)
    {
        Response.Buffer = true;
        Response.ContentType = "application/excel";
        Auxiliar aux = new Auxiliar();
        try
        {
            string Path = Server.MapPath(this.AppRelativeVirtualPath);
            FileInfo fi = new FileInfo(Path);


            byte[] plan = aux.DataTable2ExcelPlan(fi.Directory + "planplanbase.xls", fi.Directory + "planplantemp.xls", aux.CreateSampleTable(), "");
            if (plan.Length != 0)
            {
                string att = "attachment";
                Response.AddHeader("Content-Disposition", att + "; filename=planilha.xls");
                BinaryWriter bw = new BinaryWriter(Response.OutputStream);
                bw.Write(plan);
                bw.Flush();
                bw.Close();
            }
        }
        finally
        {
        }
        Response.End();

    }
}

Você poderá baixar o exemplo completo utilizando o link no final do artigo.

O design da página, como você pode ver, é bem simples. Para maiores explicações de como funciona a parte de upload, sugiro que dê uma lida nesta série de artigos, onde explico os processos que acontecem no div dvUpload, na página uploadFile.aspx e no botão btnSinalizaUpload e o porquê do botão btnProcessar está oculto e tem o seu evento OnClick disparado por outro botão :-)

Vamos começar com o botão “Exportar Dados do Grid”:

Como este botão modifica o stream de resposta da página, ele não poderá ser utilizado com AJAX.

Pera lá! Então o que ele está fazendo dentro de um UpdatePanel?

Pois é… está dentro de um UpdatePanel. Mas dentro da declaração deste UpdatePanel, foi colocada a seção <Triggers>, que serve para fazer com que os controles disparem eventos assíncronos ou não (usando AJAX ou não). Explico:

Se colocarmos na seção <Triggers> um controle PostBackTrigger, informaremos que o controle com o ID colocado no atributo ControlID irá disparar um postback normal, não disparando as rotinas AJAX.

Por outro lado, se colocarmos um controle AsyncPostBackTrigger, poderemos informar na propriedade ControlID um controle que está fora do UpdatePanel e que irá disparar as rotinas de atualização assíncrona dele, ou seja, irá funcionar com AJAX.

Vendo o código de seu evento OnClick, primeiramente mudamos o MIME type da resposta para application/excel, que quer dizer que o navegador estará recebendo uma planilha em formato Excel.

Em seguida, criamos uma instância da classe Auxiliar (variável aux), e guardamos o path completo da página na variável Path, através do método Server.MapPath (que retorna o caminho físico a partir de um caminho virtual), recebendo como parâmetro a propriedade AppRelativeVirtualPath do objeto Page.

Colocamos essa variável Path em uma instância da classe FileInfo, com a qual extrairemos a seguir somente o caminho do diretório em que a nossa aplicação está hospedada.

Agora vamos criar um Array de Byte, utilizando o método DataTable2ExcelPlan, que recebe como parâmetros uma planilha em branco, que será utilizada como base da conexão OleDB e que já deve existir no caminho proposto, uma planilha de trabalho temporária, que será criada conforme a necessidade, e por fim o DataTable a ser exportado.

Este DataTable é criado pelo mesmo método que alimenta o gridview, o método CreateSampleTable da classe Auxiliar. Se você estiver utilizando uma query para alimentar o gridview, deverá executar o mesmo método que utilizou no Bind do grid em questão.

O retorno do método DataTable2ExcelPlan é um array de bytes com o conteúdo da planilha gerada a partir do DataTable.

Se a planilha for gerada com sucesso, alteramos o header da resposta HTTP indicando que há um arquivo anexo com o método AddHeader do objeto Response, e em seguida escrevemos o array de bytes no OutputStream através de um BinaryWriter.

Na importação da planilha, acionada pelo botão btnProcessar, que está oculto na página e é disparado indiretamente através da página uploadFile.aspx, temos primeiro a verificação do arquivo na variável de sessão AREA_UPLOAD, para em seguida pegar o caminho da nossa aplicação, da mesma forma que fizemos anteriormente.

Para que a nossa conexão OleDB funcione, é necessário que a planilha exista em disco. Para isso, utilizamos um FileStream, informando em seu construtor o caminho do arquivo e o modo de operação, que setamos em FileMode.Create.

Note que no nome do arquivo que iremos salvar, colocamos o SessionID da sessão atual. Como vários usuários poderão fazer upload ao mesmo tempo, isto se torna necessário para que não haja conflitos.

Criado o FileStream, chamamos o método Write, ao qual passamos na sobrecarga que estamos utilizando um array de bytes (o arquivo que fizemos upload), a posição inicial e a quantidade de bytes a ser escrita, e em seguida fechamos o FileStream. Isto é importantíssimo, pois se o FileStream estiver aberto a nossa planilha não poderá ser lida.

Em seguida, utilizamos como DataSource do nosso gridview o método ExcelPlan2DataTable da classe Auxiliar, informando como parâmetros o caminho da planilha a ser lida e o nome da planilha dentro do arquivo XLS que queremos ler.

Damos o DataBind() no grid e voilá! A planilha aparece no grid :-)

E como essa planilha que salvamos através do FileStream é apenas temporária, no final de tudo iremos apagar este arquivo que foi gerado e remover a variável de sessão AREA_UPLOAD.

E é isso! Uma aplicação ASP.NET que faz o uso de Upload com efeitos AJAX e lendo uma planilha Excel, que com a sua imaginação poderá ser guardada em banco de dados, e outras coisas mais :-)

Um abraço e até a próxima!

Exemplo Aplicação Exportando e Importando Planilhas Excel com ASP.NET (40 KB).

Leonel Fraga de Oliveira Leonel Fraga de Oliveira é formado em Processamento de Dados na Faculdade de Tecnologia de São Paulo (FATEC-SP - 2002) e anteriormente em Técnico em Eletrônica, pela ETE Professor Aprígio Gonzaga (lá em 1999).
Atualmente trabalha como Analista de Sistemas na Prefeitura Municipal de São Caetano do Sul - SP
Tem como hobbies DJing (também trabalha como DJ freelancer) e ciclismo, além da manutenção dos sites NeoMatrix Light e NeoMatrix Tech.
Gosta de música eletrônica, tecnologia, cinema (super fã de Jornada nas Estrelas), gastronomia e outras coisas mais.


Compartilhe nas redes sociais

   

Deixe seu comentário

comments powered by Disqus