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 :

  1. Dim MeuStringBuilder As New StringBuilder("Hello World!", 25) - cria um objeto sb do tipo StringBuilder com a capacidade de 25 caracteres
  2. Dim sb As New System.Text.StringBuilder(1000)      - cria um objeto sb do tipo StringBuilder com a capacidade de 1000 caracteres

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:


José Carlos Macoratti