VB .NET - Gerando arquivos CSV a partir de um DataTable
Este artigo mostra como gerar arquivos CSV a partir de um DataTable.
O que é um arquivo CSV ?
Um arquivo CSV (Comma Separted Value) é um formato de arquivo que é normalmente usado para troca de dados entre aplicações diferentes. O arquivo no formato CSV possui os dados delimitados onde os campos são separados pelo caractere vírgula e registros separados por uma nova linha. Este formato de arquivo é usado no Microsoft Excel ,e tornou-se um pseudo padrão para a indústria mesmo entre plataformas não Microsoft.
Embora não exista uma especificação formal para o formato CSV, a RFC 4180 descreve um formato comum e estabelece o tipo MIME "text/csv" .
Um arquivo CSV é um arquivo texto delimitado que utiliza a vírgula para separar os valores existentes no arquivo, sendo que existem implementações onde outros separadores também podem ser usados.
Os arquivos CSV mais simples não permitem valores que contém vírgula (Ex: Rua Teste, 100) ou outros caracteres especiais como o indicador de nova linha CR ou LF. (Carriage Return/ Line Feed) . Implementações mais sofisticadas permitem vírgulas, ponto e vírgula(;), asterístico(*) como delimitadores e outros caracteres especiais.
Gerar arquivos CSV é muito simples e envolve conceitos básicos mas importantes que todo o desenvolvedor .NET deve conhecer.
Vamos criar uma classe que vai gerar um arquivo CSV, e, para realizar esta tarefa ela vai precisar receber como parâmetros as seguintes informações : o delimitador usado no arquivo CSV, os qualificadores usados no arquivo CSV, se o arquivo vai possuir cabeçalho e o DataTable que será a fonte de dados sobre a qual os dados serão gerados.
Vou usar o Visual Basic 2010 Express Edition que é uma ferramenta grátis para realizar esta tarefa.
Como exemplo eu vou usar o banco de dados Northwind.mdf e a tabela Categories de onde irei extrair somente os campos CategoryID, CategoryName e Description.
Criando o projeto
Abra o Visual Basic 2010 Express Edition e crie um novo projeto do tipo Windows Forms Application com o nome GerandoCSV a partir do menu File -> New Project;
No formulário padrão form1.vb vamos incluir os controles TextBox, Label, RadioButton e Button e gerar o leiaute conforme a figura abaixo:
- O delimitador será o
caractere usado para separar as colunas da tabela ao
gerar o arquivo CSV - O qualificador será o caractere que irá envolver os campos da tabela ao gerar o arquivo CSV - A informação possui cabeçalho irá gerar ou não um arquivo CVS com o nome dos cabeçalhos da tabela usada - O local de destino e nome do arquivo indica o local e nome do arquivo CSV gerado |
Para realizar o serviço pesado de gerar o arquivo vamos criar uma classe chamada ExportarCSV.
No menu Project -> Add Class selecione o template Class e informe o nome do arquivo da classe como Exportar.vb;
A seguir vamos definir o código no arquivo Exportar definindo a classe ExportarCSV:
Imports System.Text Public Class ExportarCSV Public Sub New() TextoDelimitador = ","c TextoQualificadores = """"c ColunaTemHeaders = True End Sub Public Sub New(ByVal txtDelimitador As String, ByVal txtQualificador As String, ByVal temHeaders As Boolean) TextoDelimitador = txtQualificador TextoQualificadores = txtQualificador ColunaTemHeaders = temHeaders End Sub Private _TextoDelimitador As Char Public Property TextoDelimitador() As Char Get Return _TextoDelimitador End Get Set(ByVal value As Char) _TextoDelimitador = value End Set End Property Private _TextoQualificadores As Char Public Property TextoQualificadores() As Char Get Return _TextoQualificadores End Get Set(ByVal value As Char) _TextoQualificadores = value End Set End Property Private _ColunaTemHeaders As Boolean Public Property ColunaTemHeaders() As Boolean Get Return _ColunaTemHeaders End Get Set(ByVal value As Boolean) _ColunaTemHeaders = value End Set End Property Public Function CsvDoDataTable(ByVal tabelaEntrada As DataTable) As String Try Dim CsvBuilder As New StringBuilder() If ColunaTemHeaders Then CriaHeader(tabelaEntrada, CsvBuilder) End If CriaLinhas(tabelaEntrada, CsvBuilder) Return CsvBuilder.ToString() Catch ex As Exception Throw ex End Try End Function Private Sub CriaLinhas(ByVal tabelaEntrada As DataTable, ByVal CsvBuilder As StringBuilder) Try For Each ExportarRow As DataRow In tabelaEntrada.Rows For Each ExportaColuna As DataColumn In tabelaEntrada.Columns Dim ColunaTexto As String = ExportarRow(ExportaColuna.ColumnName).ToString() ColunaTexto = ColunaTexto.Replace(TextoQualificadores.ToString(), TextoQualificadores.ToString() + TextoQualificadores.ToString()) CsvBuilder.Append(TextoQualificadores + ColunaTexto + TextoQualificadores) CsvBuilder.Append(TextoDelimitador) Next CsvBuilder.AppendLine() Next Catch ex As Exception Throw ex End Try End Sub Private Sub CriaHeader(ByVal tabelaEntrada As DataTable, ByVal CsvBuilder As StringBuilder) Try For Each ExportaColuna As DataColumn In tabelaEntrada.Columns Dim ColunaTexto As String = ExportaColuna.ColumnName.ToString() ColunaTexto = ColunaTexto.Replace(TextoQualificadores.ToString(), TextoQualificadores.ToString() + TextoQualificadores.ToString()) CsvBuilder.Append(TextoQualificadores + ExportaColuna.ColumnName + TextoQualificadores) CsvBuilder.Append(TextoDelimitador) Next CsvBuilder.AppendLine() Catch ex As Exception Throw ex End Try End Sub End Class |
A classe ExportarCSV é uma classe concreta que contém :
O namespace usado nesta classe é :
Imports System.Text
Esse namespace dá acesso a classe StringBuilder que usamos para montar o arquivo CSV antes de escrever em disco o arquivo.
Podemos pensar no objeto StringBuilder como um buffer dinâmico que pode conter uma String com a habilidade de aumentar seu tamanho a partir do zero até a capacidade final do buffer. O tamanho do buffer vai crescendo a medida que o tamanho dos caracteres presentes no objeto StringBuilder vai aumentando.
Podemos definir um número máximo de caracteres que o objeto StringBuilder pode manipular.
Este valor é chamado de capacidade do objeto e não pode ser confundido com o comprimento da string contida no objeto atual. Por exemplo podemos criar um instância da classe StringBuilder com a string "Macoratti" que possui um tamanho de 9 , e ao mesmo tempo podemos definir a capacidade máxima do objeto como sendo de 25.
Ao modificar o objeto StringBuilder , ele não faz a realocação de tamanho até que a capacidade máxima seja alcançada ; quando isto ocorre novo espaço é alocado automaticamente e a capacidade dobra de tamanho. Vejamos como podemos criar um objeto StringBuilder :
A classe System.Text.StringBuilder obtém uma melhor performance no tratamento de strings justamente porque ela aloca o espaço inicial quando uma instância do objeto é criada.
Agora vamos ao código do formulário form1.vb que é visto a seguir:
Imports System.IO Imports System.Data Imports System.Data.SqlClient Public Class Form1 Dim Csv As ExportarCSV Private Sub btnGerarCSV_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGerarCSV.Click Dim cabecalho As Boolean Dim seg As Integer = Now.Second Dim destino As String = "C:\dados\ArquivoTeste" + seg.ToString + ".csv" If validaDados() Then destino = txtDestino.Text If rdbCabecalhoSim.Checked = True Then cabecalho = True Else cabecalho = False End If Csv = New ExportarCSV(txtDelimitador.Text, txtQualificador.Text, cabecalho) Else Csv = New ExportarCSV() End If Try Using CsvWriter As New StreamWriter(destino) 'obtem o datatable e gera o arquivo csv CsvWriter.Write(Csv.CsvDoDataTable(PegaDados())) End Using If (MsgBox("Geração do arquivo concluida com sucesso. Deseja exibir o arquivo gerado ? ", MsgBoxStyle.YesNo) = DialogResult.Yes) Then System.Diagnostics.Process.Start(destino) End If Catch ex As Exception Throw ex End Try End Sub Private Function PegaDados() As DataTable Try Dim con As New SqlConnection("Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Persist Security Info=True;Integrated Security = True") Dim da As New SqlDataAdapter("SELECT CategoryID,CategoryName,Description FROM Categories", con) Dim ds As New DataSet() da.Fill(ds, "Categories") Return ds.Tables(0) Catch ex As Exception Throw ex End Try End Function Public Function validaDados() As Boolean If txtDelimitador.Text = String.Empty Then Return False ElseIf txtDelimitador.Text = String.Empty Then Return False ElseIf txtDestino.Text = String.Empty Then Return False End If Return True End Function End Class |
Ao clicar no botão - Gerar arquivo CSV - definimos um nome para o arquivo e chamamos a rotina validaDados() que verifica se as informações de delimitador, qualificador e cabeçalho foram informadas;
Em seguida criamos uma instância da classe ExportarCSV usando um dos construtores definidos;
Obtemos o DataTable usando a rotina PegaDados() onde acessamos a tabela Categories do arquivo Northwind.mdf do SQL Server;
Usamos o método CsvDoDataTable para gerar o arquivo e através do método Write do StreamWriter CsvWriter geramos o arquivo CSV.
Exibimos ou não o arquivo gerado usando a código: System.Diagnostics.Process.Start(destino) que irá abrir o arquivo no programa padrão definido para esta tarefa.
Vamos executar o programa para ver o resultado:
1- Clicando no botão - Gerar arquivo CSV - após alguns segundos teremos a janela que pergunta se desejamos exibir o arquivo gerado:
2- Como eu só o BrOffice instalado nesta máquina os sistema irá abria a janela do assistente de importação de arquivos CSV conforme abaixo:
3- Clicando em OK iremos ver o arquivo sendo exibido no programa Calc (o equivalente ao Excel) :
Conferindo o arquivo .csv no arquivo no bloco de notas veremos:
Observe o delimitador (,) , o qualificador ("") e os cabeçalhos gerados definidos na geração do arquivo CSV.
Fique a vontade para incrementar o projeto e a classe.
Pegue o projeto completo aqui : GerandoCSV.zip
Eu sei é apenas VB .NET mas eu gosto...
Jesus dizia pois aos judeus que criam nele: Se vós permanecerdes na minha palavra, verdadeiramente sereis meus discípulos. E conhecereis a verdade e a verdade os libertará.(João 8:31-32)
Referências: