You are on page 1of 13

EPPlus, o como tratar en C# con Excel en OpenXML y no morir con Interop.

Capítulo 1

hoy traigo una librería Open Source y gratuita, que me permite


superar la mayoría de las dificultades de las operaciones contra
Excel de una forma sencilla y potente: EPPlus.

Comparando Interop con EPPlus


Para definir un proyecto en Interop, lo más rápido es utilizar una
plantilla de Visual Studio de un proyecto Excel. Lo que nos
añade de forma automática las referencias necesarias a los
ensamblados que utilizaremos más adelante.

Sin embargo para que pueda añadirnos dichos ensamblados, es


conveniente instalar antes las Office Developers Tools, que
también serán referenciadas desde el proyecto.
Utilizar EPPlus, es tan sencillo como abrir el gestor de paquetes
Nuget, buscar en línea la librería EPPlus e instalarla tanto para el
proyecto principal – que no tendrá ningún problema en cohabitar
con Interop – como en el proyecto de test.

Un Excel vacía
Ahora voy a crear una Excel, con un libro y una hoja, con
ambas librerías.

INTEROP

1 using Excel = Microsoft.Office.Interop.Excel;


2
namespace GenbetaDevExcel
3
{
4 public class ExcelConInterop
5 {
6 public Excel.Application CreaNuevaExcelConInterop()
7 {
Excel.Application excel = new Excel.Application();
8 excel.Visible = false;
9
10 var workbook = excel.Workbooks.Add();
11 workbook.Sheets.Add();
12
13 string workbookPath = @"C:\Users\Juan\Desktop\ExcelInterop.xlsx";
14 workbook.SaveAs(workbookPath);
workbook.Close();
15
16 return excel;
17 }
18 }
19 }
20
21
22
EPPLUS

1
2 using System.IO;
3 using OfficeOpenXml;
4
5 namespace GenbetaDevExcel
{
6
public class ExcelConEPPlus
7 {
8 public ExcelPackage CreaNuevaExcelConEPPlus()
9 {
10 ExcelPackage excel = new ExcelPackage(new FileInfo(@"C:\Users\Juan\De
excel.Workbook.Worksheets.Add("NombreHoja");
11 excel.Save();
12
13 return excel;
14 }
15 }
16 }
17
Lo primero que he observado al hacer este ejemplo es que la
sintaxis de Interop es más completa pero más compleja.
Siendo necesario cerrar explícitamente el fichero después de su
creación, y aumentando la complejidad en el caso de que quiera
darle un nombre inicial a la hoja que obliga (ambas dos librerías)
añadir al libro de trabajo.

Para comprobar que el código funciona correctamente, he


construido un Proyecto de pruebas con los dos test siguientes -
son muy sencillitos - y tejeré la red de comprobaciones avanzadas
que surgirán más adelante en el tutorial.
?

1
2
3 using System;
4 using Microsoft.VisualStudio.TestTools.UnitTesting;
5
namespace GenbetaDevExcel
6 {
7 [TestClass]
8 public class CreaExcelTest
9 {
10 [TestMethod]
public void CreaNuevaExcel_con_Interop()
11 {
12 var constructor = new ExcelConInterop();
13
14 var excel = constructor.CreaNuevaExcelConInterop();
15
16 Assert.IsNotNull(excel);
}
17
18 [TestMethod]
19 public void CreaNuevaExcel_con_EPPlus()
20 {
21 var constructor = new ExcelConEPPlus();
22
23 var excel = constructor.CreaNuevaExcelConEPPlus();
24
Assert.IsNotNull(excel);
25 }
26 }
27 }
28
29
En la realidad casi nunca se trabaja con documentos Excel
nuevos, más bien lo que se hace es comprobar con la
librería System.IO si el fichero existe; abriéndolo, en la mayoría de
los casos, o creándolo si así fuera necesario.

Por lo cual, cuidado al relanzar los test, porque en el caso de


Interop te preguntará si quieres sustituir el fichero ya existente y
te añadirá una nueva hoja al libro de trabajo; en cambio EPPlus te
dará un error de ejecución en donde indicará que ya existe una
hoja con el nombre elegido y que no puede guardar la Excel.
Solución: borra los ficheros xslx cada vez que vayas a lanzar las
pruebas o haz una clase que compruebe si existe el fichero
para borrarlo. Otro camino es añadir un método en ambas clases
que recupere el número de hojas existentes, y añadir una nueva
solo si fuese necesario.

Con este código he completado los tres primeros puntos del índice
de ejemplos que voy a realizar en esta mini serie. En el siguiente
capítulo voy a seleccionar y grabar datos en celdas de la Excel y, si
no se alarga en demasía, introducir formulas.
EPPlus, o como tratar en C# con Excel en OpenXML y no morir con Interop.

Capitulo II

Hacer sitio antes guardar


Aunque yo me he dado cuenta refactorizando, voy a iniciar
picando un método que me borre el fichero Excel físico para
que EEPlus no se me queje (si encuentra el fichero lo abre, no lo
sustituye, y casca por querer meter elementos que ya existen), y
para que Interop no me saque la ventanita de “¿Desea
sobreescribir?”.

Así creo una clase nueva, la famosa Utilidades, y le escribo un


método estático para borrar el fichero.

?
1
2 using System.IO;
3
4 namespace GenbetaDevExcel
5 {
6 public class Utilidades
{
7 public static void BorraFichero(string path)
8 {
9 if (! string.IsNullOrWhiteSpace(path))
10 {
if (File.Exists(path))
11 { File.Delete(path); }
12 }
13 }
14 }
15 }
16
Lo siguiente que hago es desacoplar el método de guardar, para
que sea el test quien decida cuando lanzarlo y dar por acabado el
flujo de operaciones. Fíjate que en Interop, invoco el
BorraFichero() justo antes de salvar, en cambio en EPPlus no.
INTEROP

1
2 public bool GuardaExcel(Excel.Application excel)
3 {
4 try
{
5 var fichero = @"C:\Users\Juan\Desktop\ExcelInterop.xlsx";
6 Utilidades.BorraFichero(fichero);
7
8 string workbookPath = fichero;
9
10 excel.Workbooks[1].SaveAs(workbookPath);
11 excel.Workbooks[1].Close();
12
return true;
13 }
14 catch (System.Exception)
15 { return false; }
16 }
17
EPPlus

1
2 public bool GuardaExcel(ExcelPackage excel)
{
3 try
4 {
5 excel.Save();
6 return true;
7 }
catch (System.Exception)
8 { return false; }
9 }
10
Habiendo sacado el proceso de guardar, y añadiendo el borrado
al inicio del código de EPPlus, los métodos de Abrir la Excel han
quedado así.

INTEROP

1 public Excel.Application CreaNuevaExcelConInterop()


{
2 Excel.Application excel = new Excel.Application();
3 excel.Visible = false;
4 //var workbook = excel.Workbooks.Open(@"C:\Users\Juan\Desktop\Plantil
5
6 //** Añade las hojas al principio y les pone el nombre HojaX automáti
7
var workbook = excel.Workbooks.Add();
8 workbook.Sheets.Add();
9
10 return excel;
11 }
12
13
EPPlus

1
2 public ExcelPackage CreaNuevaExcelConEPPlus()
{
3 string fichero = @"C:\Users\Juan\Desktop\ExcelEPPlus.xlsx";
4 Utilidades.BorraFichero(fichero);
5
6 ExcelPackage excel = new ExcelPackage(new FileInfo(fichero));
7 excel.Workbook.Worksheets.Add("hoja1");
excel.Workbook.Worksheets.Add("hoja2");
8
9 return excel;
10 }
11
Una curiosidad es el orden en que se insertan las nuevas hojas en
el libro de trabajo. En EPPlus las va añadiendo a la última posición
con el nombre que le he introducido, en cambio en Interop se
añaden siempre en la segunda posición a partir del inicio, y le
pone el nombre (en español) hojaXXXX, donde XXXX es un
número autoincremental.

Selección de celdas y rangos de


celdas
El rudimento mínimo básico de las operaciones contra una Excel
es el seleccionar una celda o un rango de celdas, y escribir en
ellas.
INTEROP

1
public Excel.Application EscribeEnRangoDeCeldas(Excel.Application excel)
2 {
3 Excel.Worksheet hojaActual = excel.Workbooks[1].Worksheets[1];
4 hojaActual.Cells.get_Range("A1").Value2 = "Esto funciona!";
5
6 var rangoDeCeldas = hojaActual.Cells.get_Range("$C$1:$C$3");
7 rangoDeCeldas = hojaActual.Cells.get_Range("C1:C3");
8
return excel;
9 }
10
EPPlus

1
public ExcelPackage EscribeEnRangoDeCeldas(ExcelPackage excel)
2
{
3 var hojaActual = excel.Workbook.Worksheets["hoja1"];
4 hojaActual = excel.Workbook.Worksheets[1];
5
6 hojaActual.Cells["A1"].Value = "Esto funciona!";
7 var rangoDeCeldas = hojaActual.Cells["C1:C3"];
rangoDeCeldas = hojaActual.Cells["$C$1:$C$3"];
8
9 return excel;
10 }
11
Para comprobar que el funcionamiento es correcto, he realizado
dos test que lanzan la creación de la Excel, realizan el método de
escribir y salvan.

INTEROP

?
[TestMethod]
1
public void EscribeEnRangoDeCeldas_con_Interop()
2 {
3 var constructor = new ExcelConInterop();
4 var excel = constructor.CreaNuevaExcelConInterop();
5
6 constructor.EscribeEnRangoDeCeldas(excel);
constructor.GuardaExcel(excel);
7
8 Assert.IsNotNull(excel);
9 }
10
11
EPPlus

1
2 [TestMethod]
public void EscribeEnRangoDeCeldas_con_EPPlus()
3 {
4 var constructor = new ExcelConEPPlus();
5 var excel = constructor.CreaNuevaExcelConEPPlus();
6
7 constructor.EscribeEnRangoDeCeldas(excel);
constructor.GuardaExcel(excel);
8
9 Assert.IsNotNull(excel);
10 }
11
Para no darle complejidad al código la forma de comprobar que
ha escrito correctamente es abrir la Excel y revisar que sea así.

Introduciendo fórmulas
¿Qué sería de Excel si no fuera por las fórmulas? Sin duda no
tendría sentido una hoja de cálculo sin poder introducir
definiciones de operaciones. Así voy a introducir dos valores en
dos celdas, y en una tercera inserto la formula que suma ambos
valores.

Aquí ambas sintaxis son muy parecidas, siempre un poco más fea
la de Interop. En cambio la obligación de tener un Excel completo
instalado en la máquina donde se ejecuta el código – el mayor
inconveniente de esta forma de trabajar, y más con servidores
cloud en PaaS – es que permite hacer cosas que EPPlus no.

INTEROP

1
public Excel.Application SumaDosCeldas(Excel.Application excel)
2 {
3 Excel.Worksheet hojaActual = (Excel.Worksheet) excel.Workbooks[1].Worksheets
4
5 hojaActual.Cells.get_Range("A5").Value2 = "150";
6 hojaActual.Cells.get_Range("B5").Value2 = "100";
7 hojaActual.Cells.get_Range("A10").Formula = "=SUM(A5:B5)";
8
return excel;
9 }
10
EPPlus

1
public ExcelPackage SumaDosCeldas(ExcelPackage excel)
2
{
3 var hojaActual = excel.Workbook.Worksheets["hoja1"];
4 hojaActual = excel.Workbook.Worksheets[1];
5
6 hojaActual.Cells["A5"].Value = 150;
7 hojaActual.Cells["B5"].Value = 100;
hojaActual.Cells["A10"].Formula = "=SUM(A5:B5)";
8
9 return excel;
10 }
11
La principal, para mi gusto, es que como EPPlus no incorpora un
motor de cálculo, no puedo recuperar el valor del resultado de
una celda que contiene una fórmula. Cosa que con Interop sí que
puedo.

También me he encontrado con un problema irresoluble con


hojas de datos grandes o muy grandes ya que EPPlus,
simplemente, casca. Mientras Interop aguanta mucho más.
Por ello no he hecho test recuperando el resultado de la suma, si
no meros lanzadores de los métodos.

INTEROP

1
2 [TestMethod]
public void SumaDosCeldas_con_Interop()
3
{
4 //** Interop deja recuperar el valor del resultado de la formula
5 //** EEPlus, no.
6 var constructor = new ExcelConInterop();
7 var excel = constructor.CreaNuevaExcelConInterop();
constructor.SumaDosCeldas(excel);
8 constructor.GuardaExcel(excel);
9
10 Assert.IsNotNull(excel);
11 }
12
EPPlus

1
2 [TestMethod]
public void SumaDosCeldas_con_EPPlus()
3 {
4 var constructor = new ExcelConEPPlus();
5 var excel = constructor.CreaNuevaExcelConEPPlus();
6 constructor.SumaDosCeldas(excel);
constructor.GuardaExcel(excel);
7
8 Assert.IsNotNull(excel);
9 }
10
Y para comprobar que la suma está bien y que resulta en 250, lo
que hago es abrir los ficheros.
Ahora dejo para el siguiente capítulo, y posiblemente final, algo
un poco más avanzado y que es el introducir una imagen y una
gráfica en la hoja.