Trabalhando com arquivos de planilha excel no C# com EPPlus

Criação, leitura ou escrita em arquivos excel no C# utilizando a biblioteca EPPlus - que não exige Microsoft Office instalado para funcionar.

(Update : conversão de excel para pdf em apps desktop - clique aqui).
(Update 2: leitura e escrita de arquivo excel já existente - clique aqui)


Oilá senhores! Nosso novo post é sobre uma opção para criarmos, lermos ou escrevermos em arquivos excel no C#: utilizando a biblioteca EPPlus. Ela é bem cheia de recursos, tem bastante documentação na internet e, melhor: não exige que o Office esteja instalado no servidor ou computador que gerará o arquivo - ela é independente! Ela lê e escreve planilhas tranquilamente, tanto para aplicações web quanto para desktop.

Eu já utilizo essa biblioteca há bastante tempo. Ela é muito simples de usar. Já precisei usar fórmulas, imagens, formatações, entre outras coisas, e em tudo ela me atendeu. A única limitação dela, por enquanto, é que ela só trabalha com arquivo .xlsx - até dá pra salvar em .xls, mas vai dar que o arquivo possui formato inválido ao ser aberto.

A página da ferramente é http://epplus.codeplex.com/ . Espero que não tenham problema com inglês, porque a maior parte das referências encontradas na internet está em inglês - o que é comum para nossa área. Vou mostrar um pouco aqui como ela funciona, mas depois vocês voarão com as próprias asas e degustarão muito de todo o conteúdo relacionado que você poderá encontrar ;) Até hoje não fiquei com dúvidas sem encontrar respostas, graças às colaborações dos colegas.

Antes de começar... lembro que aqui vou deixar alguns exemplos de uso, mas não são os únicos e melhores que existem, beleza? Explorem outros meios de usar a biblioteca.

Gerando um arquivo excel para ser salvo no computador

Vamos utilizar nossa aplicação da Livraria Jujubinhas no exemplo, mas em uma versão para desktop ou console application. Façamos de conta que precisamos disponibilizar para o usuário uma planilha excel com os livros e autores cadastrados, como na figura a seguir:
  Exemplo de arquivo Excel

Primeiro de tudo, vou baixar a biblioteca da EPPlus e adicioná-la às referências do projeto, como é de praxe.

Após criar a classe e o método para gerar o arquivo, nele vou criar uma instância de ExcelPackage. Ele é a classe da biblioteca que vai gerenciar o arquivo excel que você precisa. Um dos meios para instanciar ExcelPackage é informando a pasta e o nome do arquivo excel (que precisa ter extensão .xlsx); se o arquivo já existir, ele vai lê-lo, senão ele será criado. Além disso, os arquivos excel são organizados em planilhas, e por isso vou criar uma planilha chamada "Livros" dentro deste arquivo acessando o workbook do excelpackage:
 
public void Gerar(List<Livro> livros)
 {
    // criando/abrindo o arquivo:
    FileInfo caminhoNomeArquivo = new FileInfo(@"C:\Users\Aline Rigues\Documents\teste.xlsx");
    ExcelPackage arquivoExcel = new ExcelPackage(caminhoNomeArquivo);

    // CRIANDO (ADD) uma planilha neste arquivo e obtendo a referência para meu código operá-la.
    ExcelWorksheet planilha = arquivoExcel.Workbook.Worksheets.Add("Livros");

    // (operações para gerar o arquivo)
}

Agora, com a referência da planilha, basta eu escrever os meus dados dentro dela. No excel, os dados são escritos dentro de células, e por isso vamos escrever também dentro das células da nossa planilha:
 
   // ESCREVENDO O CABECALHO
   // Uma forma de escrever: informando endereco da celula
   planilha.Cells["A1"].Value = "Livraria Jujubinhas";
   // Outra forma de escrever: informando linha e coluna da celula
   int linha = 1, coluna = 2;
   planilha.Cells[linha, coluna].Value = "O doce, colorido e irresistível mundo dos livros";

Bora então iniciar a criação do arquivo do exemplo escrevendo os dados dos livros com o que temos até o momento. Vou utilizar um iterador para andar pelas linhas e colunas da planilha:
 
   // linhas e colunas das células começam no 1
   int linha = 1;
   int coluna = 1;

   // Escrevendo cabeçalho principal
   planilha.Cells[linha++, coluna].Value = "Livraria Jujubinhas";
   planilha.Cells[linha++, coluna].Value = "O doce, colorido e irresistível mundo dos livros";
   linha++;
   planilha.Cells[linha++, coluna].Value = "Relação de livros e autores";
   linha++;

   // Escrevendo cabecalho tabela
   planilha.Cells[linha, coluna++].Value = "Categoria";
   planilha.Cells[linha, coluna++].Value = "Título";
   planilha.Cells[linha, coluna++].Value = "Autores";
   planilha.Cells[linha, coluna++].Value = "Preço";
   linha++;

   // Escrevendo tabela
   foreach(Livro livro in livros)
   {
      coluna = 1;
      planilha.Cells[linha, coluna++].Value = livro.Categoria.Descricao;
      planilha.Cells[linha, coluna++].Value = livro.Titulo;
      planilha.Cells[linha, coluna++].Value = livro.GetNomesAutores();
      planilha.Cells[linha, coluna++].Value = livro.Preco;
      linha++;
   }

   // salvando e fechando o arquivo: MUITO IMPORTANTE HEIN!!!
   arquivoExcel.Save();
   arquivoExcel.Dispose();

Pra criar, escrever e salvar em um arquivo excel é basicamente isso.

O exemplo tem mais algumas coisinhas, como mesclar células, mudar a cor do fundo, colocar bordas na tabela e outras coisas. Nessas horas, pode ser mais vantajoso trabalhar com intervalo de células, ao invés de trabalhar uma por uma:
 
// Abordando um intervalo de células:  modo planilha.Cells[linhaInicial, colunaInicial, linhaFinal, colunaFinal]
   planilha.Cells[linha, coluna, linha, coluna + 3].Merge = true; // mesclando células
   planilha.Cells[linha++, coluna].Value = "Livraria Jujubinhas";
   // Abordando um intervalo de células:  modo planilha.Cells[stringComIntervalo]
   planilha.Cells[&quot;A2:D2&quot;].Merge = true; // mesclando células
   planilha.Cells[&quot;A2&quot;].Value = "O doce, colorido e irresistível mundo dos livros";

Vamos aplicar algumas estilizações e formatações necessárias. Não vou aprofundar muito porque vocês podem obter na internet os comandos para fazerem tudo o que quiserem com a EPPlus - dica: utilizem termos em inglês.
 
   planilha.Cells[linha, coluna].Style.Font.Bold = true;           // Deixando negrito uma célula
   planilha.Cells[linha, coluna].Style.Font.Size = 16;             // Aplicando tamanho 18 na fonte
   planilha.Cells[linha, coluna].Style.Font.Name = "Calibri";      // Fonte
   planilha.Cells[linha, coluna].Style.Font.Color.SetColor(Color.IndianRed); // Cor da fonte
   planilha.Cells[linha, coluna].Value = "Livraria Jujubinhas";
   linha++;

(...)

   // Escrevendo cabecalho tabela
   planilha.Cells[linha, coluna, linha, coluna + 4].Style.Fill.PatternType = ExcelFillStyle.Solid;     // preenchimento de fundo sólido
   planilha.Cells[linha, coluna, linha, coluna + 4].Style.Fill.BackgroundColor.SetColor(Color.Aqua);   // cor do preenchimento de fundo
   planilha.Cells[linha, coluna, linha, coluna + 4].Style.Font.Bold = true;           // Deixando negrito o cabecalho da tabela
   planilha.Cells[linha, coluna++].Value = "Categoria";
   planilha.Cells[linha, coluna++].Value = "Título";
   planilha.Cells[linha, coluna++].Value = "Autores";
   planilha.Cells[linha, coluna++].Value = "Preço";
   linha++;

(...)

Enfim. O código finalizado vou deixar disponível neste link. Basta eu chamar o método da classe em algum ponto do meu código e o arquivo será criado e salvo onde determinei. Mas, mais interessante que esse exemplo é um código de exemplo que a própria EPPlus disponibiliza neste link: https://epplus.codeplex.com/discussions/431223.

Eu costumo criar um arquivo separado para gerar cada excel, e dentro dele criar métodos para cada parte do arquivo (método CriarCabecalho, EscreverRegistros, FormatarPlanilha, etc). Pra fins didáticos, este código que disponibilizei contém um único método que faz tudo.

Gerando um arquivo excel para ser exibido na web (MVC)

Olhem que legal: vou utilizar a mesma classe do exemplo anterior, GeraListaLivrosExcel.cs, e gerar o mesmo arquivo, agora pra exibir para um visitante de uma aplicação web. Porém, haverão algumas mudanças na classe.

A princípio, vamos precisar de uma controller que gere o arquivo e devolva para o usuário. Porém, como a controller vai devolver um arquivo e não uma view, seu retorno vai precisar ser do tipo FileResult, ao invés da costumeira ActionResult.
 
// Controller
public FileResult ListarLivrosExcel()
{
   // Um exemplo retornando um arquivo ao invés de uma view
   String nomeArquivo = "ArquivoQualquer.png";
   byte[] bytesArquivo = ObterBytesArquivo();
   String tipoArquivo = "image/png";
   return File(bytesArquivo, tipoArquivo, nomeArquivo);
}

Agora, vamos precisar alterar o código da minha classe geradora de planilha, para que ela forneça o arquivo excel pra minha controller exibir, ao invés de salvar em disco. Para isso, haverão duas mudanças:

1º - Ao criar o ExcelPackage, eu não vou precisar fornecer um caminho para o arquivo. Ele será criado apenas em memória.

2º - Vou realizar todo o processo de criação e retornar o ExcelPackage do meu método, para que minha controller possa exibir meu arquivo para o visitante. Como não vou precisar salvar meu arquivo em lugar nenhum, retirarei o comando planilha.Save(). E, para manipular o arquivo na controller, ele precisará estar aberto ainda, então vou tirar também o comando planilha.Dispose() daqui - o dispose deverá ser dado na controller após as operações necessárias para exibição.

Resumindo as alterações no método da classe geradora:
 
// metodo agora retorna ExcelPackage
public ExcelPackage Gerar(List<Livro> livros)
{
   // criando o arquivo em memória
   ExcelPackage arquivoExcel = new ExcelPackage(); // nao recebe mais o caminho do arquivo

   //(operacoes para construir o arquivo do mesmo jeito que antes)

   // Salvando e fechando o arquivo - desnecessários agora
   //arquivoExcel.Save();
   //arquivoExcel.Dispose();            

   return arquivoExcel; // retornando o arquivo aberto em memória para a controller
}

Lá na controller, vou criar uma instância da minha classe geradora e receber o arquivo excel dela em uma varíavel. Como a responsabilidade de fechar o arquivo e liberar memória agora é da controller, uma forma de fazer isso é usar um bloco using, que liberará a variável após o fim do bloco.
 
   // Controller
   public FileResult ListarLivrosExcel()
   {
      List<Livro> livros = this.Repositorio.Obter().ToList();

      // Gerando minha planilha e recebendo-a
      using (ExcelPackage arquivoExcel = new GeraListaLivrosExcel().Gerar(livros))
      {
         //(operacoes para transformar o ExcelPackage para ser retornado para a View)

         return File(?, ?, ?); // E agora?
      }
    }

Por último, precisamos transformar o ExcelPackage para ser possível retorná-lo no método File(). Se vocês consultarem a sobrecarga do método File(), verão que ele aceita, entre os outros parâmetros: cadeia de bytes, uma Stream ou o caminho do arquivo que precisa ser exibido. Neste exemplo, vamos inserir o conteúdo da planilha dentro de uma Stream, já que existe um método na ExcelPackage que viabiliza isso: o SaveAs(). Feito isso, bastará fornecer um nome para o arquivo e informar o tipo do retorno:
 
E pronto! Quando o usuário chamar a controller, ela irá devolver o arquivo excel para ele.
 
  Arquivo Excel sendo devolvido para usuário

É isso aí! :) Hora de vocês explorarem e contribuírem!


Update, galera! Vamos converter este excel em PDF?

Pessoal, precisei recentemente gerar meus arquivos excel e depois convertê-los em PDF. Encontrei uma ferramenta que faz isso, a Spire.xls.

Para ter acesso à ela, entrem no site da Ice Blue, que é a desenvolvedora: http://www.e-iceblue.com/Download/download-excel-for-net-now.html e baixem a versão standard. Vocês deverão instalar a ferramenta e depois copiar as DLLs na pasta bin do programa instalado, inserindo-as como referências do seu projeto.

O desenvolvedor que encontrou essa bênção deixou a seguinte postagem explicando como utilizar o EPPlus para gerar o excel e, logo após, chamar a Spire para converter o excel em PDF:

http://www.c-sharpcorner.com/UploadFile/48c038/create-excel-and-convert-it-to-pdf-by-free-api/

Mas, resumindo a postagem dele, a conversão foi feita em uma aplicação Desktop e de uma maneira hiper simples: depois que você gerar e salvar seu excel, apenas crie um objeto Workbook (da Spire), passe o caminho do excel e salve como pdf. Assim:
 
   Workbook workbook = new Workbook();
   //Load excel file
   workbook.LoadFromFile("Caminho/MeuArquivo.xlsx");
   //Save excel file to pdf file.
   workbook.SaveToFile("Caminho/MeuArquivo.pdf", Spire.Xls.FileFormat.PDF);

Para aplicação web, ainda não testei se tem como utilizar a Spire para realizar a conversão em tempo real.

Referências

Site do EPPlus - http://epplus.codeplex.com/

Tabela de constantes de cores da System.Drawing.Color - http://www.flounder.com/csharp_color_table.htm


UPDATE - Leitura e escrita de arquivo já existente

Atendendo ao comentário do colega Walbert, vamos ver um pequeno trecho de código para abrir um arquivo Excel já existente, realizando leitura e escrita no mesmo.

Como eu disse, qualquer dúvida sobre o EPPlus pode ser solucionada na Internet, visto a boa documentação e utilização dele. Bastou eu dar uma pesquisada de 5 minutos sobre o pedido, construir o código fonte abaixo em 10 minutos e testá-lo.

O código a seguir é uma Controller que abre, altera o arquivo, salva e depois lê o arquivo modificado para exibir seu conteúdo na View através de uma String.
 
        public ActionResult MexeExcel()
        {
            // Caminho do meu arquivo (coloquei na pasta Content da minha aplicação MVC)
            string filePath = Server.MapPath(Url.Content("~/Content/arquivos/planilha.xlsx"));
            
            // Abrindo, modificando meu arquivo e salvando
            ExcelPackage package = new ExcelPackage(new FileInfo(filePath));
            ExcelWorksheet workSheet = package.Workbook.Worksheets.First();
            DateTime hoje = DateTime.Now;
            int lastRow = workSheet.Dimension.End.Row;
            workSheet.Cells[1, 1].Value = hoje.ToString(); // sobrescrevendo primeira linha e coluna
            workSheet.Cells[lastRow + 1, 1].Value = hoje.ToString(); // inserindo data de hoje apos ultima linha, 1a coluna
            package.Save();
            package.Dispose();

            // Abrindo meu arquivo para varrer o conteudo da primeira planilha e exibir na minha página
            package = new ExcelPackage(new FileInfo(filePath));
            workSheet = package.Workbook.Worksheets.First();
            StringBuilder conteudo = new StringBuilder();
            for (int i = workSheet.Dimension.Start.Row; i <= workSheet.Dimension.End.Row;i++)
            {
                for (int j = workSheet.Dimension.Start.Column; j <= workSheet.Dimension.End.Column; j++)
                {
                    conteudo.Append( "["+ workSheet.Cells[i, j].Value + "]" );
                }
                conteudo.Append("<br/>");
            }
            package.Dispose();
            return View((object) conteudo.ToString());
        }
Solução encontrada em  https://codealoc.wordpress.com/2012/04/19/reading-an-excel-xlsx-file-from-c/ .
 

7 comentários

avatar
Robson em 05/05/2017 disse:
Obrigado. Ajudou muito. Responder
avatar
walbert em 29/05/2017 disse:
Como faço para usar uma planilha já criada? Com as minhas formatações, pq neste código ele cria a planilha. Responder
avatar
Aline Rigues em 30/05/2017 disse:
Olá, Walbert. Acrescentei um trecho de código ao final do post para responder sua pergunta. Basta abrir o arquivo e trabalhar com ele. Um abraço e obrigada pela visita! Responder
avatar
Walbert em 01/06/2017 disse:
Opá, muito obrigado pela ajuda.
avatar
Everson em 23/08/2017 disse:
Como faria para ler um arquivo Excel já existente e mostrar em um data grid view? Responder
avatar
Arthur Leite em 19/10/2017 disse:
Olá Aline, Excelente artigo. Você poderia disponibilizar o código para gerar o arquivo para o usuário usando MVC? Não consegui localizar no artigo a parte da criação do método "Repositorio" e a sintaxe final da FileResult que retorna o File(). Grato, Arthur Responder
avatar
Ivan em 28/03/2018 disse:
Esta solução free de gerar PDF é limitada em 200 linhas por planilha. Conhece alguma solução que seja free e sem limitação ? Obrigado Responder

Envie seu comentário