Como crio um arquivo do Excel (.XLS e .XLSX) em C # sem instalar o Microsoft Office?

1892

Como criar uma planilha do Excel com C # sem exigir a instalação do Excel na máquina que está executando o código?

mistrmark
fonte
O "... sem instalar o Ms Office?" parte da pergunta parece pouco profissional. Você pode gerar qualquer tipo de arquivo a partir de um programa C # (com um arquivo xlsou xlsxum deles). Não é um requisito que exista um programa no seu computador que possa lê-lo (por exemplo, binário).
28519 Mike
30
@ Mike A peça "sem a necessidade de instalar o Excel" não tem nada a ver com ser profissional. É sobre dependências. O texto original da pergunta tinha a seguinte redação: "Idealmente, eu gostaria de código aberto, para não precisar adicionar dependências de terceiros ao meu código e evitar o uso do Excel diretamente para criar o arquivo (usando OLE Automation.) " É lamentável que a questão tenha sido drasticamente simplificada.
Tony
5
Supondo que você estava tentando fazer algo sem biblioteca ou código externo, não posso falar por arquivos xls, mas por arquivos xlsx, por que não começar pegando um existente, renomeando-o para um arquivo zip e explorando o conteúdo? Um pouco de engenharia reversa lhe dirá bastante. Existem vários arquivos xml e arquivos rels diferentes nas várias pastas e subpastas. Tente explorar isso e veja se é algo que você pode replicar ou se pode encontrar documentação nos vários namespaces / esquemas xml.
Alexander Ryan Baggett
@AlexanderRyanBaggett Isso foi extremamente útil! Deparei com este post enquanto trabalhava na geração automática de relatórios e explorava documentos como um arquivo zip fornece algumas informações sobre o que é necessário para criar um arquivo de documento.
SentientFlesh 5/03

Respostas:

1055

Você pode usar uma biblioteca chamada ExcelLibrary. É uma biblioteca gratuita e de código aberto publicada no Google Code:

ExcelLibrary

Parece ser uma porta do PHP ExcelWriter que você mencionou acima. Ele ainda não gravará no novo formato .xlsx, mas eles estão trabalhando para adicionar essa funcionalidade no.

É muito simples, pequeno e fácil de usar. Além disso, possui um DataSetHelper que permite usar DataSets e DataTables para trabalhar facilmente com dados do Excel.

O ExcelLibrary parece ainda funcionar apenas para o formato antigo do Excel (arquivos .xls), mas pode estar adicionando suporte no futuro para os formatos mais recentes do 2007/2010.

Você também pode usar o EPPlus , que funciona apenas para arquivos no formato Excel 2007/2010 (arquivos .xlsx). Há também NPOI que funciona com ambos.

Existem alguns erros conhecidos em cada biblioteca, conforme observado nos comentários. Ao todo, o EPPlus parece ser a melhor escolha com o passar do tempo. Parece ser mais ativamente atualizado e documentado também.

Além disso, conforme observado por @ АртёмЦарионов abaixo, o EPPlus tem suporte para Tabelas Dinâmicas e o ExcelLibrary pode ter algum suporte ( problema de tabela dinâmica no ExcelLibrary )

Aqui estão alguns links para referência rápida:
ExcelLibrary - GNU Lesser GPL
EPPlus - GNU Lesser General Public License (LGPL)
NPOI - Licença Apache

Aqui estão alguns exemplos de código para o ExcelLibrary:

Aqui está um exemplo pegando dados de um banco de dados e criando uma pasta de trabalho a partir dele. Observe que o código ExcelLibrary é a única linha na parte inferior:

//Create the data set and table
DataSet ds = new DataSet("New_DataSet");
DataTable dt = new DataTable("New_DataTable");

//Set the locale for each
ds.Locale = System.Threading.Thread.CurrentThread.CurrentCulture;
dt.Locale = System.Threading.Thread.CurrentThread.CurrentCulture;

//Open a DB connection (in this example with OleDB)
OleDbConnection con = new OleDbConnection(dbConnectionString);
con.Open();

//Create a query and fill the data table with the data from the DB
string sql = "SELECT Whatever FROM MyDBTable;";
OleDbCommand cmd = new OleDbCommand(sql, con);
OleDbDataAdapter adptr = new OleDbDataAdapter();

adptr.SelectCommand = cmd;
adptr.Fill(dt);
con.Close();

//Add the table to the data set
ds.Tables.Add(dt);

//Here's the easy part. Create the Excel worksheet from the data set
ExcelLibrary.DataSetHelper.CreateWorkbook("MyExcelFile.xls", ds);

Criar o arquivo do Excel é tão fácil quanto isso. Você também pode criar manualmente arquivos do Excel, mas a funcionalidade acima é o que realmente me impressionou.

Mike Webb
fonte
247
A ExcelLibrary foi substituída pelo excepcional EPPlus - epplus.codeplex.com . Jan atualiza-o regularmente. O utilizamos e é um dos melhores projetos de código aberto com os quais trabalhamos.
Mark A
3
Deve-se observar que o ExcelLibrary tem muitos problemas de desempenho ao lidar com grandes conjuntos de dados (maiores que 5000 linhas e muitas colunas). Atualmente, fazemos uma modificação pesada da base de código no trabalho para que possamos usá-la em um projeto.
Rossisdead 18/10/11
O EPPlus parece muito menos problemático que o ExcelLibrary, mas é GPL e, portanto, apenas uma solução para projetos de código aberto.
Seth
6
E o ClosedXML ? Talvez eu seja útil em seus projetos.
Amadeus Sánchez
589

Se você está satisfeito com o formato xlsx, experimente meu projeto GitHub, EPPlus . Tudo começou com a fonte do ExcelPackage, mas hoje é uma reescrita total. Ele suporta intervalos, estilo de célula, gráficos, formas, imagens, intervalos nomeados, AutoFiltro e muitas outras coisas.

Jan Källman
fonte
77
A licença agora é LGPL, notas de versão aqui: epplus.codeplex.com/releases/view/79802
Simon D
13
Os exemplos foram úteis. Consegui mudar meu código de usar a biblioteca de interoperabilidade da Microsoft (horrivelmente lenta) para esta biblioteca (versão 4.x) em algumas horas. Meu benchmark grava um arquivo com duas guias e cerca de 750.000 células. Usando a interoperabilidade MS, demorou 13 minutos. Usando o EPPlus, levou 10 segundos, uma aceleração de aproximadamente 80x. Muito feliz!
Paul Chernoch
3
Para maior clareza neste tópico, a LGPL permite que o software seja vinculado sem que a parte infecciosa da GPL ocorra. Você só precisa abrir as alterações de código-fonte que fizer no ClosedXml ou, se colocar diretamente o código-fonte (em vez de referenciar os assemblies do ClosedXml) dentro do seu aplicativo, precisará abri-lo.
Chris Marisic
4
@ Paul Chernoch: Preenchemos grandes folhas de Excel com interoperabilidade muito rapidamente. O segredo é fazer uma atualização em massa. Crie um bloco de objeto [,], preencha-o e, em seguida, grave essa matriz no Excel: excelWorksheet.get_Range (range) .Value2 = block;
21718 Marc Markett
2
Parece que o licenciamento está passando da LGPL para a licença Polyform Noncommercial 1.0.0
Luke
175

E quanto ao uso do Open XML SDK 2.0 para Microsoft Office?

Alguns benefícios:

  • Não requer o Office instalado
  • Feito pela Microsoft = documentação decente do MSDN
  • Apenas uma dll .Net para usar no projeto
  • O SDK vem com muitas ferramentas como diff, validator, etc.

Ligações:

Sogger
fonte
3
Importante observar que a DLL para isso tem pouco mais de 5 MB e está limitada aos formatos do Office 2007. Mas certamente a solução mais fácil e rápida que funciona para mim.
Josh Brown
18
Apenas um aviso de que a versão 2.5 está disponível e pode ser baixada aqui .
Snuffleupagus
10
O SDK modela o XML em classes, para que cada tag XML seja mapeada para uma tag e, em seguida, você deve criar a hierarquia de classes (cada instância possui uma coleção de instâncias / tags filho) corretamente. Isso significa que você precisa conhecer a estrutura XML de um arquivo do Excel, o que é muito complicado. É muito mais fácil usar um invólucro como o EPPlus, mencionado acima, que simplifica as coisas.
Tsahi Asher
2
Uma excelente amostra do Microsoft Open XML SDK - Open XML Writer pode ser encontrada em polymathprogrammer.com/2012/08/06/… ou consulte a solução Stack Overflow stackoverflow.com/questions/11370672/…
Greg
4
Eu achei o Open XML Writer do Microsoft Open XML SDK ótimo. Usando as soluções acima, (especialmente a amostra de Vincent Tom (Poly Math)), é fácil criar um escritor que transmita grandes conjuntos de dados e grave registros de maneira semelhante e não muito mais complexa do que você faria por CSV; mas você está escrevendo xml. Open XML é a mentalidade em que a Microsoft considera os novos formatos do Office. E você sempre pode renomeá-los de arquivos .xslx para .zip, se desejar cutucar o conteúdo XML.
1874 Greg Greg
167

Usei com sucesso os seguintes projetos de código aberto:

  • ExcelPackage para formatos OOXML (Office 2007)

  • NPOI para o formato .XLS (Office 2003). O NPOI 2.0 (Beta) também suporta XLSX.

Dê uma olhada nas minhas postagens no blog:

Criando planilhas do Excel .XLS e .XLSX em C #

NPOI com tabela do Excel e gráfico dinâmico

Leniel Maccaferri
fonte
6
Uma observação nas referências NPOI - Linha e Coluna é baseada em zero. Funciona bem para preencher um modelo existente.
John M
108

Você pode usar o OLEDB para criar e manipular arquivos do Excel. Verifique isto: Lendo e escrevendo Excel usando OLEDB .

Exemplo típico:

using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\temp\\test.xls;Extended Properties='Excel 8.0;HDR=Yes'"))
{
  conn.Open();
  OleDbCommand cmd = new OleDbCommand("CREATE TABLE [Sheet1] ([Column1] string, [Column2] string)", conn);
  cmd.ExecuteNonQuery();
}

EDIT - Mais alguns links:

Panos
fonte
4
Alguém pode confirmar se isso funciona quando executado em x64? Tenho certeza de que o Jet só funcionará se seu aplicativo estiver compilado ou em execução no modo de 32 bits.
Lamar
2
Acabei testado esta conexão e ele falhou em um Windows Server 2008 R2 x64 RC, parece que um tem que instalar o driver do 2007 Office System: Componentes de Conectividade de Dados [ microsoft.com/downloads/...
Chris Richner
25
Tenha muito cuidado com isso - é uma grande confusão feia (por exemplo, às vezes adivinha um tipo de coluna e descarta todos os dados que não se encaixam).
dbkk 29/09/09
9
Deve-se ter muito cuidado ao usar esse método. Eu achei muito esquisito para dados que não estão em um formato perfeito.
Kenny Mann
9
Como uma pessoa que teve que usar o OleDb em um grande projeto, eu digo FIQUE LONGE! Às vezes, não é possível recuperar um valor de célula apenas porque não conseguia entender o formato. Não possui uma operação de exclusão. Funciona totalmente diferente e imprevisível, mesmo com uma menor mudança de provedor. Eu diria que vá para uma solução comercial comprovada.
Caner Öncü 13/09/14
80

A solução comercial, SpreadsheetGear for .NET , fará isso.

Você pode ver exemplos ao vivo do ASP.NET (C # e VB) aqui e baixar uma versão de avaliação aqui .

Isenção de responsabilidade: Eu possuo SpreadsheetGear LLC

Joe Erickson
fonte
10
Você tem um ótimo produto, mas acho que muitas pessoas aqui esperam soluções gratuitas. Isso pode explicar os votos negativos.
md1337
65

Algumas opções que usei:

Se o XLSX for obrigatório: o ExcelPackage é um bom começo, mas morreu quando o desenvolvedor parou de trabalhar nele. O ExML pegou a partir daí e adicionou alguns recursos. O ExML não é uma opção ruim, ainda o estou usando em alguns sites de produção.

Para todos os meus novos projetos, estou usando o NPOI , a porta .NET do Apache POI . O NPOI 2.0 (Alpha) também suporta XLSX.

Nate
fonte
Cuidado com o ExcelPackage se precisar oferecer suporte ao XLS. Eu tive dificuldade com isso e, finalmente, mudei para o ExcelLibrary.
Jeremy
Definitivamente verdade. O ExcelPackage / ExML é apenas uma boa opção se você precisar do suporte XLSX.
Nate
5
Observe que o ExcelPackage possui um sucessor: EPPlus ( epplus.codeplex.com ), que suporta XLSX. Minha única preocupação, em comparação com o NPOI, por exemplo, é o desempenho, por exemplo, quando há muitas colunas.
Pragmateek
63

Uma opção extremamente leve pode ser usar tabelas HTML. Basta criar tags de cabeça, corpo e tabela em um arquivo e salve-o como um arquivo com uma extensão .xls. Existem atributos específicos da Microsoft que você pode usar para estilizar a saída, incluindo fórmulas.

Sei que você pode não estar codificando isso em um aplicativo Web, mas aqui está um exemplo da composição de um arquivo do Excel por meio de uma tabela HTML. Essa técnica pode ser usada se você estiver codificando um aplicativo de console, aplicativo de desktop ou serviço.

ponto e vírgula esquecido
fonte
6
É tão ad hoc, mas funciona (sem mencionar o Excel emitindo um aviso de abertura) e é tão simples que merece ter um lugar como solução. Embora apenas para mostrar que você pode exportar um arquivo excel :))
Luka Ramishvili
3
Esta solução funcionou bem para mim, apenas, note que você não pode usar extensão .xlsx
Jill
Algumas pessoas da minha organização não podem abrir arquivos do Excel criados dessa maneira no Office 2010 e acima. Não sei qual é o problema, mas tive que rolar minha própria implementação OpenXML. (ver resposta de Sogger)
Kristen Hammack
49

Se você estiver criando arquivos do Excel 2007/2010, experimente este projeto de código aberto: https://github.com/closedxml/closedxml

Ele fornece uma maneira orientada a objetos para manipular os arquivos (semelhante ao VBA) sem lidar com os aborrecimentos dos documentos XML. Pode ser usado por qualquer linguagem .NET como C # e Visual Basic (VB).

O ClosedXML permite criar arquivos do Excel 2007/2010 sem o aplicativo Excel. O exemplo típico é a criação de relatórios do Excel em um servidor da web:

var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Sample Sheet");
worksheet.Cell("A1").Value = "Hello World!";
workbook.SaveAs("HelloWorld.xlsx");
Armfoot
fonte
9
Eu tentei usar isso em um projeto que cria planilhas do Excel bem grandes. Excelente biblioteca, mas extremamente pobre em desempenho. Acabei de fazer uma comparação para o projeto no qual estou trabalhando: o ClosedXML (v 0.53.3) levou 92.489 ms, enquanto o EPPlus (v 2.9.03, para teste - não podemos usar porque é GPL) levou 16.500 ms.
Druid
1
@Druid a licença é LGPL supondo que você não modifique o código fonte para ClosedXML é livre para uso epplus.codeplex.com/license
Chris Marisic
48

Você pode usar o ExcelXmlWriter .

Funciona bem.

Petr Snobelt
fonte
47

Você pode realmente querer verificar as classes de interoperabilidade disponíveis em C # (por exemplo, Microsoft.Office.Interop.Excelvocê diz não OLE (o que não é esse), mas as classes de interoperabilidade são muito fáceis de usar. Confira a documentação em C # aqui (a Interop for Excel inicia em página 1072 do PDF em C #).

Você pode ficar impressionado se não os tiver experimentado.

Esteja avisado da posição da Microsoft sobre isso:

No momento, a Microsoft não recomenda e não oferece suporte a aplicativos de automação do Microsoft Office de qualquer aplicativo ou componente cliente não interativo e autônomo (incluindo serviços ASP, ASP.NET, DCOM e NT), porque o Office pode exibir um comportamento instável e / ou impasse quando o Office é executado nesse ambiente.

GEOCHET
fonte
6
Mas você tem que se certificar de que você descarta tudo manualmente, caso contrário você irá vazar memória
MagicKat 29/08/08
8
@ Ricky B: Além disso, na minha experiência com a interoperabilidade, é que ele usa o Excel. Sempre que o usamos, se o Excel não estivesse instalado na máquina, obteríamos exceções de COM.
MagicKat
1
Com o OLE, mesmo com descartes muito cuidadosos, ele eventualmente vaza memória ou trava. Isso é aceitável para aplicativos / estações de trabalho atendidos, mas para servidores não é recomendado (a Microsoft possui um KB informando isso). Para o nosso servidor, apenas o reiniciamos todas as noites. Novamente, isso funciona bem.
Jennifer Zouak
11
@ Geoffrey: ah OK, você vai me fazer trabalhar para isso :) -> support.microsoft.com/kb/257757 No momento, a Microsoft não recomenda e não oferece suporte à automação de aplicativos do Microsoft Office a partir de aplicativos não assistidos e não-assistidos. aplicativo cliente interativo ...
Jennifer Zouak 01/11/10
4
Estou chegando a essa discussão depois de lutar mais de uma semana na interoperabilidade e, a menos que suas necessidades sejam muito simples, isso não vai funcionar. O suporte para formatar sua planilha é péssimo, razão pela qual é possível gerar um arquivo .xls e não apenas um arquivo .csv simples. Por exemplo, você tentou gerar mais de 911 caracteres em uma célula ou tentou definir a largura das células mescladas de maneira consistente? Eu tenho, e não posso te dizer o quanto odeio essa porcaria agora ... Faça um favor a si mesmo e vá com uma das bibliotecas gratuitas mencionadas nesta discussão.
Md1337
34

Aqui está um C # biblioteca completamente livre, que permite a exportação a partir de um DataSet, DataTableouList<> em um arquivo .xlsx Excel 2007 genuína, usando as bibliotecas OpenXML:

http://mikesknowledgebase.com/pages/CSharp/ExportToExcel.htm

O código fonte completo é fornecido - gratuitamente - junto com instruções e um aplicativo de demonstração.

Depois de adicionar esta classe ao seu aplicativo, você pode exportar o DataSet para o Excel em apenas uma linha de código:

CreateExcelFile.CreateExcelDocument(myDataSet, "C:\\Sample.xlsx");

Não fica muito mais simples do que isso ...

E nem sequer exige que o Excel esteja presente no seu servidor.

Mike Gledhill
fonte
1
Isso parece um pouco enganador, pois você está pedindo uma doação para obter todos os recursos.
precisa saber é o seguinte
Isso é parcialmente verdade: a versão totalmente gratuita gera um arquivo .xlsx perfeito para você e todo o código-fonte é fornecido. Se você doar US $ 10 ou mais a uma dessas duas instituições de caridade (das quais não recebo absolutamente nada), obterá uma versão "melhor" mostrando como executar formatação, datas etc. Dado o custo de produtos de terceiros, eu acho doar US $ 10 para uma boa causa vale a pena!
Mike Gledhill
23

Você pode dar uma olhada no GemBox.Spreadsheet .

Eles têm uma versão gratuita com todos os recursos, mas limitados a 150 linhas por folha e 5 folhas por pasta de trabalho, se isso atender às suas necessidades.

Ainda não precisei usá-lo, mas parece interessante.

ManiacZX
fonte
21

O Syncfusion Essential XlsIO pode fazer isso. Ele não depende do Microsoft office e também oferece suporte específico para diferentes plataformas.

Exemplo de código:

//Creates a new instance for ExcelEngine.
ExcelEngine excelEngine = new ExcelEngine();
//Loads or open an existing workbook through Open method of IWorkbooks
IWorkbook workbook = excelEngine.Excel.Workbooks.Open(fileName);
//To-Do some manipulation|
//To-Do some manipulation
//Set the version of the workbook.
workbook.Version = ExcelVersion.Excel2013;
//Save the workbook in file system as xlsx format
workbook.SaveAs(outputFileName);

Todo o conjunto de controles está disponível gratuitamente através do programa de licença da comunidade , se você se qualificar (menos de 1 milhão de dólares em receita). Nota: Eu trabalho para o Syncfusion.

Davis Jebaraj
fonte
18

Bem,

você também pode usar uma biblioteca de terceiros como o Aspose .

Essa biblioteca tem o benefício de não exigir que o Excel seja instalado em sua máquina, o que seria ideal no seu caso.

Dimi Toulakis
fonte
Para ser mais preciso, você pode usar o Aspose.Cells for .NET para criar arquivos do Excel (XLS, XLSX) em seu aplicativo .NET.
Shahzad Latif
9
Sim, você pode, se não se importa em pagar uma taxa mínima de licença de US $ 999. Experimente a biblioteca MikesKnowledgeBase ... que custa US $ 999 mais barato que isso !!
Mike Gledhill
17

O OpenXML também é uma boa alternativa que ajuda a evitar a instalação do MS Excel no servidor.O Open XML SDK 2.0 fornecido pela Microsoft simplifica a tarefa de manipular pacotes Open XML e os elementos subjacentes do esquema Open XML em um pacote. A API (Open XML Application Programming Interface) encapsula muitas tarefas comuns que os desenvolvedores executam nos pacotes Open XML.

Confira isto OpenXML: alternativa que ajuda a evitar a instalação do MS Excel no servidor

Sachin Dhir
fonte
17

As várias bibliotecas XML do Office 2003 disponíveis funcionam muito bem para arquivos excel menores. No entanto, acho que o tamanho de uma grande pasta de trabalho salva no formato XML é um problema. Por exemplo, uma pasta de trabalho com a qual trabalho teria 40 MB no novo formato XLSX (e reconhecidamente mais compactado) se torna um arquivo XML de 360 ​​MB.

Tanto quanto minha pesquisa me levou, existem dois pacotes comerciais que permitem a saída para os formatos de arquivos binários mais antigos. Eles são:

Nem são baratos (500 USD e 800 USD respectivamente, eu acho). mas ambos funcionam independentemente do próprio Excel.

O que eu gostaria de saber é o módulo de saída do Excel para os gostos do OpenOffice.org. Gostaria de saber se eles podem ser portados de Java para .Net.

biozinco
fonte
Este funciona em .net e java, e não é caro. SmartXLS smartxls.com
liya
15

Recentemente, usei o FlexCel.NET e achei uma excelente biblioteca! Não digo isso sobre muitos produtos de software. Não adianta dar todo o discurso de vendas aqui, você pode ler todos os recursos em seu site.

É um produto comercial, mas você obtém a fonte completa se o comprar. Então, suponho que você possa compilá-lo em sua montagem, se realmente quiser. Caso contrário, é apenas um conjunto extra para o xcopy - sem configuração ou instalação ou algo assim.

Eu não acho que você encontrará nenhuma maneira de fazer isso sem bibliotecas de terceiros, pois o .NET Framework, obviamente, não possui suporte embutido e a Automação OLE é apenas um mundo de dores.

EMP
fonte
15

Eu escrevi um código simples para exportar o conjunto de dados para o Excel sem usar o objeto Excel usando System.IO.StreamWriter.

Abaixo está o código que lerá todas as tabelas do conjunto de dados e as escreverá nas planilhas uma a uma. Eu peguei a ajuda deste artigo .

public static void exportToExcel(DataSet source, string fileName)
{
        const string endExcelXML = "</Workbook>";
        const string startExcelXML = "<xml version>\r\n<Workbook " +
                 "xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\r\n" +
                 " xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n " +
                 "xmlns:x=\"urn:schemas-    microsoft-com:office:" +
                 "excel\"\r\n xmlns:ss=\"urn:schemas-microsoft-com:" +
                 "office:spreadsheet\">\r\n <Styles>\r\n " +
                 "<Style ss:ID=\"Default\" ss:Name=\"Normal\">\r\n " +
                 "<Alignment ss:Vertical=\"Bottom\"/>\r\n <Borders/>" +
                 "\r\n <Font/>\r\n <Interior/>\r\n <NumberFormat/>" +
                 "\r\n <Protection/>\r\n </Style>\r\n " +
                 "<Style ss:ID=\"BoldColumn\">\r\n <Font " +
                 "x:Family=\"Swiss\" ss:Bold=\"1\"/>\r\n </Style>\r\n " +
                 "<Style     ss:ID=\"StringLiteral\">\r\n <NumberFormat" +
                 " ss:Format=\"@\"/>\r\n </Style>\r\n <Style " +
                 "ss:ID=\"Decimal\">\r\n <NumberFormat " +
                 "ss:Format=\"0.0000\"/>\r\n </Style>\r\n " +
                 "<Style ss:ID=\"Integer\">\r\n <NumberFormat " +
                 "ss:Format=\"0\"/>\r\n </Style>\r\n <Style " +
                 "ss:ID=\"DateLiteral\">\r\n <NumberFormat " +
                 "ss:Format=\"mm/dd/yyyy;@\"/>\r\n </Style>\r\n " +
                 "</Styles>\r\n ";
        System.IO.StreamWriter excelDoc = null;
        excelDoc = new System.IO.StreamWriter(fileName);

        int sheetCount = 1;
        excelDoc.Write(startExcelXML);
        foreach (DataTable table in source.Tables)
        {
            int rowCount = 0;
            excelDoc.Write("<Worksheet ss:Name=\"" + table.TableName + "\">");
            excelDoc.Write("<Table>");
            excelDoc.Write("<Row>");
            for (int x = 0; x < table.Columns.Count; x++)
            {
                excelDoc.Write("<Cell ss:StyleID=\"BoldColumn\"><Data ss:Type=\"String\">");
                excelDoc.Write(table.Columns[x].ColumnName);
                excelDoc.Write("</Data></Cell>");
            }
            excelDoc.Write("</Row>");
            foreach (DataRow x in table.Rows)
            {
                rowCount++;
                //if the number of rows is > 64000 create a new page to continue output
                if (rowCount == 64000)
                {
                    rowCount = 0;
                    sheetCount++;
                    excelDoc.Write("</Table>");
                    excelDoc.Write(" </Worksheet>");
                    excelDoc.Write("<Worksheet ss:Name=\"" + table.TableName + "\">");
                    excelDoc.Write("<Table>");
                }
                excelDoc.Write("<Row>"); //ID=" + rowCount + "
                for (int y = 0; y < table.Columns.Count; y++)
                {
                    System.Type rowType;
                    rowType = x[y].GetType();
                    switch (rowType.ToString())
                    {
                        case "System.String":
                            string XMLstring = x[y].ToString();
                            XMLstring = XMLstring.Trim();
                            XMLstring = XMLstring.Replace("&", "&");
                            XMLstring = XMLstring.Replace(">", ">");
                            XMLstring = XMLstring.Replace("<", "<");
                            excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" +
                                           "<Data ss:Type=\"String\">");
                            excelDoc.Write(XMLstring);
                            excelDoc.Write("</Data></Cell>");
                            break;
                        case "System.DateTime":
                            //Excel has a specific Date Format of YYYY-MM-DD followed by  
                            //the letter 'T' then hh:mm:sss.lll Example 2005-01-31T24:01:21.000
                            //The Following Code puts the date stored in XMLDate 
                            //to the format above
                            DateTime XMLDate = (DateTime)x[y];
                            string XMLDatetoString = ""; //Excel Converted Date
                            XMLDatetoString = XMLDate.Year.ToString() +
                                 "-" +
                                 (XMLDate.Month < 10 ? "0" +
                                 XMLDate.Month.ToString() : XMLDate.Month.ToString()) +
                                 "-" +
                                 (XMLDate.Day < 10 ? "0" +
                                 XMLDate.Day.ToString() : XMLDate.Day.ToString()) +
                                 "T" +
                                 (XMLDate.Hour < 10 ? "0" +
                                 XMLDate.Hour.ToString() : XMLDate.Hour.ToString()) +
                                 ":" +
                                 (XMLDate.Minute < 10 ? "0" +
                                 XMLDate.Minute.ToString() : XMLDate.Minute.ToString()) +
                                 ":" +
                                 (XMLDate.Second < 10 ? "0" +
                                 XMLDate.Second.ToString() : XMLDate.Second.ToString()) +
                                 ".000";
                            excelDoc.Write("<Cell ss:StyleID=\"DateLiteral\">" +
                                         "<Data ss:Type=\"DateTime\">");
                            excelDoc.Write(XMLDatetoString);
                            excelDoc.Write("</Data></Cell>");
                            break;
                        case "System.Boolean":
                            excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" +
                                        "<Data ss:Type=\"String\">");
                            excelDoc.Write(x[y].ToString());
                            excelDoc.Write("</Data></Cell>");
                            break;
                        case "System.Int16":
                        case "System.Int32":
                        case "System.Int64":
                        case "System.Byte":
                            excelDoc.Write("<Cell ss:StyleID=\"Integer\">" +
                                    "<Data ss:Type=\"Number\">");
                            excelDoc.Write(x[y].ToString());
                            excelDoc.Write("</Data></Cell>");
                            break;
                        case "System.Decimal":
                        case "System.Double":
                            excelDoc.Write("<Cell ss:StyleID=\"Decimal\">" +
                                  "<Data ss:Type=\"Number\">");
                            excelDoc.Write(x[y].ToString());
                            excelDoc.Write("</Data></Cell>");
                            break;
                        case "System.DBNull":
                            excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" +
                                  "<Data ss:Type=\"String\">");
                            excelDoc.Write("");
                            excelDoc.Write("</Data></Cell>");
                            break;
                        default:
                            throw (new Exception(rowType.ToString() + " not handled."));
                    }
                }
                excelDoc.Write("</Row>");
            }
            excelDoc.Write("</Table>");
            excelDoc.Write(" </Worksheet>");
            sheetCount++;
        }


        excelDoc.Write(endExcelXML);
        excelDoc.Close();
    }
Harsha.Vaswani
fonte
1
Como o artigo diz, porém, é XML que o Excel lê em vez de ser um arquivo XLS, o que significa que ele pode funcionar apenas no Excel e não em outros programas que lêem planilhas. Mas é provavelmente melhor do que a tabela HTML equivalente responde aqui!
Rup
Suporta xlsx ? OpenXML ?
21817 Kiquenet
14

Só quero adicionar outra referência a uma solução de terceiros que lida diretamente com seu problema: http://www.officewriter.com

(Aviso: trabalho para a SoftArtisans, a empresa que fabrica o OfficeWriter)

Eisbaer
fonte
13

IKVM + POI

Ou você pode usar o Interop ...

MagicKat
fonte
12

Aqui está uma maneira de fazer isso com o LINQ to XML, completo com o código de exemplo:

Importe e exporte rapidamente dados do Excel com LINQ to XML

É um pouco complexo, já que você precisa importar espaços para nome e assim por diante, mas permite evitar dependências externas.

(Além disso, é claro, é VB .NET, não C #, mas você sempre pode isolar o material VB .NET em seu próprio projeto para usar XML Literals e fazer todo o resto em C #.)

Kyralessa
fonte
12

Alguns fornecedores de componentes de terceiros, como Infragistics ou Syncfusion, oferecem recursos de exportação do Excel muito bons que não exigem a instalação do Microsoft Excel.

Como esses fornecedores também fornecem componentes avançados de grade da interface do usuário, esses componentes são particularmente úteis se você deseja que o estilo e o layout de uma exportação do Excel imitem o estado atual de uma grade na interface do usuário do seu aplicativo.

Se sua exportação se destina a ser executada no lado do servidor, com ênfase nos dados a serem exportados e sem nenhum link para a interface do usuário, eu optaria por uma das opções de código aberto gratuitas (por exemplo, ExcelLibrary).

Eu já participei de projetos que tentaram usar a automação do lado do servidor no pacote Microsoft Office. Com base nessa experiência, eu recomendaria fortemente contra essa abordagem.

Simen S
fonte
12
public class GridViewExportUtil
{
    public static void Export(string fileName, GridView gv)
    {
        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.AddHeader(
            "content-disposition", string.Format("attachment; filename={0}", fileName));
        HttpContext.Current.Response.ContentType = "application/ms-excel";

        using (StringWriter sw = new StringWriter())
        {
            using (HtmlTextWriter htw = new HtmlTextWriter(sw))
            {
                //  Create a form to contain the grid
                Table table = new Table();

                //  add the header row to the table
                if (gv.HeaderRow != null)
                {
                    GridViewExportUtil.PrepareControlForExport(gv.HeaderRow);
                    table.Rows.Add(gv.HeaderRow);
                }

                //  add each of the data rows to the table
                foreach (GridViewRow row in gv.Rows)
                {
                    GridViewExportUtil.PrepareControlForExport(row);
                    table.Rows.Add(row);
                }

                //  add the footer row to the table
                if (gv.FooterRow != null)
                {
                    GridViewExportUtil.PrepareControlForExport(gv.FooterRow);
                    table.Rows.Add(gv.FooterRow);
                }

                //  render the table into the htmlwriter
                table.RenderControl(htw);

                //  render the htmlwriter into the response
                HttpContext.Current.Response.Write(sw.ToString());
                HttpContext.Current.Response.End();
            }
        }
    }

    /// <summary>
    /// Replace any of the contained controls with literals
    /// </summary>
    /// <param name="control"></param>
    private static void PrepareControlForExport(Control control)
    {
        for (int i = 0; i < control.Controls.Count; i++)
        {
            Control current = control.Controls[i];
            if (current is LinkButton)
            {
                control.Controls.Remove(current);
                control.Controls.AddAt(i, new LiteralControl((current as LinkButton).Text));
            }
            else if (current is ImageButton)
            {
                control.Controls.Remove(current);
                control.Controls.AddAt(i, new LiteralControl((current as ImageButton).AlternateText));
            }
            else if (current is HyperLink)
            {
                control.Controls.Remove(current);
                control.Controls.AddAt(i, new LiteralControl((current as HyperLink).Text));
            }
            else if (current is DropDownList)
            {
                control.Controls.Remove(current);
                control.Controls.AddAt(i, new LiteralControl((current as DropDownList).SelectedItem.Text));
            }
            else if (current is CheckBox)
            {
                control.Controls.Remove(current);
                control.Controls.AddAt(i, new LiteralControl((current as CheckBox).Checked ? "True" : "False"));
            }

            if (current.HasControls())
            {
                GridViewExportUtil.PrepareControlForExport(current);
            }
        }
    }
}

Olá, esta solução é exportar sua visualização em grade para o seu arquivo Excel. Isso pode ajudá-lo

Gaurav
fonte
7
Não, isso gera HTML marcado como um arquivo do Excel em vez de um arquivo do Excel verdadeiro. Sim, o próprio Excel abrirá o OK, mas outros programas que consomem planilhas - incluindo o visualizador gratuito do Microsoft, por exemplo - não o aceitarão. É melhor criar um arquivo real do Excel usando uma das bibliotecas aqui.
quer
Você também deve usar System.Net.Mime.ContentDisposition para gerar o texto do cabeçalho da disposição do conteúdo em vez de um acréscimo de sequência - que lidará com os nomes de arquivos que contêm espaços etc. corretamente.
Rup
12

Você pode criar arquivos Excel bem formatados usando esta biblioteca: http://officehelper.codeplex.com/documentation
Veja abaixo a amostra:

using (ExcelHelper helper = new ExcelHelper(TEMPLATE_FILE_NAME, GENERATED_FILE_NAME))
{
    helper.Direction = ExcelHelper.DirectionType.TOP_TO_DOWN;
    helper.CurrentSheetName = "Sheet1";
    helper.CurrentPosition = new CellRef("C3");

    //the template xlsx should contains the named range "header"; use the command "insert"/"name".
    helper.InsertRange("header");

    //the template xlsx should contains the named range "sample1";
    //inside this range you should have cells with these values:
    //<name> , <value> and <comment>, which will be replaced by the values from the getSample()
    CellRangeTemplate sample1 = helper.CreateCellRangeTemplate("sample1", new List<string> {"name", "value", "comment"}); 
    helper.InsertRange(sample1, getSample());

    //you could use here other named ranges to insert new cells and call InsertRange as many times you want, 
    //it will be copied one after another;
    //even you can change direction or the current cell/sheet before you insert

    //typically you put all your "template ranges" (the names) on the same sheet and then you just delete it
    helper.DeleteSheet("Sheet3");
}        

onde a amostra se parece com isso:

private IEnumerable<List<object>> getSample()
{
    var random = new Random();

    for (int loop = 0; loop < 3000; loop++)
    {
        yield return new List<object> {"test", DateTime.Now.AddDays(random.NextDouble()*100 - 50), loop};
    }
}
desconhecidos
fonte
10

A maneira mais simples e rápida de criar um arquivo do Excel a partir do C # é usar a Open XML Productivity Tool. A Open XML Productivity Tool vem com a instalação do Open XML SDK. A ferramenta faz a engenharia reversa de qualquer arquivo do Excel em código C #. O código C # pode então ser usado para gerar novamente esse arquivo.

Uma visão geral do processo envolvido é:

  1. Instale o Open XML SDK com a ferramenta
  2. Crie um arquivo do Excel usando o cliente mais recente do Excel com a aparência desejada. Dê um nome DesiredLook.xlsx.
  3. Com a ferramenta aberta DesiredLook.xlsxe clique no botão Reflect Code próximo à parte superior. insira a descrição da imagem aqui
  4. O código C # do seu arquivo será gerado no painel direito da ferramenta. Adicione isso à sua solução C # e gere arquivos com a aparência desejada.

Como um bônus, esse método funciona para qualquer arquivo do Word e do PowerPoint. Como desenvolvedor de C #, você fará alterações no código para atender às suas necessidades.

Eu desenvolvi um aplicativo WPF simples no github que será executado no Windows para esse fim. Há uma classe de espaço reservado chamada GeneratedClassonde você pode colar o código gerado. Se você voltar uma versão do arquivo, ele gerará um arquivo do Excel como este:

insira a descrição da imagem aqui

Taterhead
fonte
1
Ainda não experimentei esta solução Open XML SDK, mas uau, definitivamente vou dar uma olhada. Eu trabalhei com ferramentas como essa por muitos anos e não sabia sobre essa. Publiquei minha própria simples FOSS para a conversão para XLSX com .NET: github.com/TonyGravagno/NebulaXConvert
TonyG