VB .NET - Formatando arquivos textos
No artigo de hoje eu vou tratar de um assunto recorrente: a formatação de arquivos textos. |
Não é raro o desenvolvedor ter que realizar tarefas de formatação de arquivos textos recebidos de legados quer gerando ou recebendo tais arquivos e tendo que realizar sua formatação.
Neste artigo veremos como é simples realizar o tratamento de strings usando os recursos do VB .NET. Para quem é o do tempo do Clipper, nada comparado ao trabalho que o programador Clipper tinha que fazer para realizar as mesmas tarefas. (Fiz um curso de Clipper na Nantucket)
Clipper (ou CA-Clipper) é um compilador 16 bits da linguagem xBase para o ambiente DOS. Foi criada em 1984 com o propósito de ser um compilador para o Ashton-Tate dBase, um gerenciador de banco de dados muito popular em sua época. |
Para ilustrar vamos supor que você trabalha em uma empresa e como programador VB .NET recebeu a seguinte tarefa:
1- Você irá receber um arquivo texto no seguinte formato:
9800009038,1 9857007038,1 9907010027,1 9567012027,1 9568009038,1 ..... |
Este arquivo é recebido de um legado e representa a relação de produtos recebidos por uma filial da empresa.
2- A informação contida no arquivo é a seguinte:
Cada linha de texto possui duas informações separadas por uma vírgula sendo que a primeira parte representa o código e a cor do produto e a segunda parte a quantidade do produto.
Na primeira parte da linha temos um número que se apresenta composto de duas informações :
Dessa forma, para clarear o entendimento, temos:
linha 1 - 9800009038,1
código do produto = 9800
Cor do produto (sempre 6 dígitos) = 009038
quantidade = 1
Pois bem, o seu trabalho será receber o tal arquivo e tratá-lo realizando a seguinte formatação:
1- O código do produto deve ser
extraído e alinhado a esquerda;
2- A cor do produto deve ser alinhada 20 posições a partir do código
do produto;
3- A quantidade do produto deve ser alinhada 15 posições a
partir da cor do produto;
A seguir temos uma ilustração de como o serviço deverá ser feito:
cod.Produto cor Produto Qtde
Arquivo texto recebido | Arquivo texto formatado |
É uma tarefa simples para que conhece o VB .NET que oferece diversas classes para tratar arquivos textos.
Vamos então rever algumas dessas classes e como usá-las para resolver o problema acima.
Criando o projeto no Visual Basic Express Edition
Abra o Visual Basic 2010 Express Edition e no menu File-> New Project, crie um novo projeto do tipo Windows Forms Application com o nome Gerar_Arquivo_Texto;
No formulário padrão form1.vb vamos incluir a partir da ToolBox os seguinte controles:
Conforme o leiaute da figura abaixo:
Este singelo programa irá atuar da seguinte forma:
A seguir vemos uma figura exibindo o programa em execução realizando a tarefa proposta:
Vamos agora definir o código do nosso programa.
A primeira coisa a fazer é identificar as classes que iremos usar para realizar as tarefas de acesso e formatação do arquivo texto. Essas classes se encontram no namespace System.IO por isso vamos definir no início do formulário a declaração :
Imports System.IO
A seguir , logo a após a declaração da classe do formulário form1, vamos definir algumas variáveis visíveis no formulário
Dim nomeArquivoDestino As String = "c:\dados\ArquivoTextoDestino.txt" Dim nomeArquivoDestinoPadrao As String = "c:\dados\ArquivoTextoDestino.txt" Dim nomearquivoOrigem As String = "c:\dados\ArquivoTexto.txt" Dim nomearquivoOrigemPadrao As String = "c:\dados\ArquivoTexto.txt" Dim linha As String = "" Dim linhaFormatada As String = "" |
Essas variáveis definem o nome do arquivo de origem e destino, a linha e a linhaFormatada que iremos usar para formatar o arquivo texto.
No evento Click do botão - btnOrigem - que fica ao lado da primeira caixa de texto, vamos definir o código que usa o controle OpenFileDialog e que irá abrir a caixa de diálogo para procurar o arquivo origem , selecioná-lo e exibir o seu nome na caixa de texto.
Private Sub btnOrigem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOrigem.Click 'define o titulo, pasta inicial e o multiselect como false Me.ofdOrigem.Multiselect = False Me.ofdOrigem.Title = "Selecionar Arquivos" ofdOrigem.InitialDirectory = "C:\dados" 'filtra para exibir somente arquivos textos ofdOrigem.Filter = "Texto (*.txt)|*.txt|" & "Texto (*.txt)|*.txt*" ofdOrigem.CheckFileExists = True ofdOrigem.CheckPathExists = True ofdOrigem.FilterIndex = 2 ofdOrigem.RestoreDirectory = True ofdOrigem.ReadOnlyChecked = True ofdOrigem.ShowReadOnly = True 'atribui nome do arquivo de origema a caixa de texto origem If ofdOrigem.ShowDialog() = DialogResult.OK Then nomearquivoOrigem = ofdOrigem.FileName txtArquivoOrigem.Text = nomearquivoOrigem Else nomearquivoOrigem = nomearquivoOrigemPadrao txtArquivoOrigem.Text = nomearquivoOrigem End If End Sub |
No evento Click do botão - Gerar Arquivo Texto Formatado - temos a rotina que inicia a formatação do arquivo texto origem. O código é o seguinte:
Private Sub btnExibeTexto_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExibeTexto.Click lstDados.Items.Clear() lstFormatado.Items.Clear() gerarArquivoTextFormatado() End Sub |
O código da rotina gerarArquivoTextoFormatado() é quem inicia o trabalho de formatação e seu código é dado a seguir:
Private Sub gerarArquivoTextFormatado() ' limpa os listbox lstDados.Items.Clear() lstFormatado.Items.Clear() Try 'verifica se existe o arquivo de origem If File.Exists(txtArquivoOrigem.Text) Then 'verifica se ja existe o arquivo formatado e avisa o usuário If File.Exists(nomeArquivoDestino) = True Then MessageBox.Show("Atenção !!! Já existe arquivo de destino formatado, se você não apagar o arquivo o arquivo gerado terá o conteúdo em duplicidade.", "Gerar arquivo Formatado", MessageBoxButtons.OK, MessageBoxIcon.Information) End If 'abre arquivo texto usando a declaração using Using r As StreamReader = New StreamReader(nomearquivoOrigem) ' define a linha como String. Dim linha As String 'le primeira linha linha = r.ReadLine ' percorre cada linha no arquivo enquanto a linha contiver dados Do While (Not linha Is Nothing) 'exibe a linha lstDados.Items.Add(linha) ' le a proxima linha e formata linha lstFormatado.Items.Add(formataLinha(linha)) 'gera arquivo formatado geraArquivoFormatado(formataLinha(linha)) 'le proxima linha linha = r.ReadLine Loop End Using Else MsgBox("Arquivo " + nomearquivoOrigem + " não localizado ") End If Catch ex As Exception MsgBox("Ocorreu um erro durante a geração do arquivo : " & ex.Message) End Try End Sub |
O VB.NET introduziu um novo forma orientada a
objetos de trabalhar com arquivos . O namespace System.IO fornece diversas classes para trabalhar com
arquivos textos , arquivos binários e streams de bytes.
As classes contém diversos métodos para as operações mais
comuns com arquivos : copiar , excluir, manipular os
atributos , etc...
Para ler arquivos textos vamos usar a classe StreamReader e os métodos Read e Readline. Para escrever em arquivos textos iremos usar
a classe StreamWriter e os métodos Write e WriteLine.
Geralmente quando vamos tratar arquivos
textos e realizar operações de leitura e escrita precisamos
verificar se um determinado arquivo existe , fazemos isto usando
a classe System.IO.File
que possui os seguintes métodos
:
AppendText | Cria um StreamWriter anexa texto UTF-8 a um arquivo existente. |
Copy | Overloaded. Copia um arquivo existente para um novo arquivo. |
Create | Overloaded. Cria um arquivo no diretório especificado. |
CreateText | Cria ou abre um novo arquivo para escrita. |
Delete | Exclui um arquivo definido |
Exists | Determina se um arquivo existe. |
GetAttributes | Obtêm os atributos do arquivo especificado. |
GetCreationTime | Retorna a data e hora de criação para o arquivo ou pasta definido. |
GetLastAccessTime | Retorna a data e hora de criação para o arquivo ou pasta definido acessado pela última vez. |
GetLastWriteTime | Retorna a data e hora de criação para o arquivo ou pasta definido escrito pela última vez. |
Move | Move um arquivo definido para um novo local. |
Open | Overloaded. Abre um FileStream no caminho indicado. |
OpenRead | Abre um arquivo para leitura. |
OpenText | Abre um arquivo existente para leitura.(UTF-8) |
OpenWrite | Abre um arquivo existente para escrita. |
A função formataLinha é quem realmente realiza a formatação de cada linha:
Private Function formataLinha(ByVal linha As String) As String 'define as variaveis locais usadas Dim codProd As String Dim corProd As String Dim qtdProd As String Dim tamanho As Integer Dim linhaFormatada As String = "" Dim strArr() As String Try 'separa as linhas do arquivo texto em um array de strings strArr = linha.Split(",") 'obtem o tamanho do array tamanho = strArr(0).Length 'obtem o código do produto codProd = strArr(0).Substring(0, tamanho - 6) 'alinha o codigo do produto codProd = codProd.PadRight(20) 'obtem a cor do produto corProd = strArr(0).Substring(tamanho - 6, 6) 'alinha a cor do produto corProd = corProd.PadRight(15) 'obtem a quantidade do produto qtdProd = strArr(1) 'monta a linha formatada linhaFormatada = codProd + corProd + qtdProd Return linhaFormatada Catch ex As Exception Throw ex End Try End Function |
Vamos entender como o código acima funciona:
- Declaramos a variável strArr() como um array de strings para receber cada linha que é extraída do arquivo texto
- O código linha.split(",") separa a linha em duas partes a partir da vírgula. Dessa forma a linha "9800009038,1" será armazenada em duas partes no array: str(0)=9800009038 e str(1)=1;
Obs: Na verdade a função Split retorna um array de única dimensão contendo o número de substrings separadas no processo dependendo do critério e delimitador usado.
- Tratando a primeira parte obtemos tamanho da string armazenada em strArr(0) usando o método Length. Assim para str(0)=9800009038 temos que tamanho=10;
- Como sabemos que o
código do produto tem um tamanho fixo de 4 obtemos o seu valor
no código: strArr(0).Substring(0, tamanho - 6)
onde usamos o método Substring(0,tamanho-6)
que extrai tamanho-6 (=4) posições a partir da
posição zero a string referente ao código do produto. Para a
string 9800009038 obtemos temos que trArr(0).Substring(0,
4) e obtemos o código do produto: 9800
- Alinhamos o código do produto a esquerda com preenchendo a direita com espaços até 20 posições usando a função PadRight(20)
PadLeft
e PadRight são usados para preencher uma
string (PadLeft- preenche com
caracter(es) à esquerda e PadRight -
preenche com caracter(es) à direita). Sintaxe: PadRight(tamanho,caractere) , PadLeft(tamanho,caractere) Onde: tamanho
= O tamanho a ser preenchido Exemplo: PadRight(10, "0") => alinha a sequência de caracteres a esquerda e preenche com zero até 10 posições a direita Ex: Dim nome as String = "Macoratti" => nome.PadRight(20,"0") => resultado = "Macoratti00000000000" Obs: Se o caractere não for especificado serão usados espaços em branco para o preenchimento PadRight(n) - Alinha à esquerda os caracteres de uma seqüência de caracteres, preenchendo à direita com espaços ou um caractere Unicode especificado, para um tamanho total n especificado. Para PadLeft() o funcionamento é idêntico mas o preenchimento ocorre à esquerda. Ex: Dim nome as String = "Macoratti" => nome.PadLeft(20,"0") => resultado = "00000000000Macoratti" |
- Extraímos a cor do produto usando o código : strArr(0).Substring(tamanho - 6, 6) onde a função Substring extrai 6 posições a string a partir da posição tamanho-6 (=4)
- Alinhamos a cor do produto a esquerda preenchendo com espaços até 15 posições à direita usando o código: corProd = corProd.PadRight(15)
A rotina geraArrquivoFormatado recebe a linha formatada e a escreve no arquivo de destino:
Private Sub geraArquivoFormatado(ByVal linha As String) Try Using writer As New StreamWriter(nomeArquivoDestino, True) writer.WriteLine(linha) End Using Catch ex As Exception MsgBox(ex.Message) End Try End Sub |
Para exibir o último arquivo de destino formatado temos no evento Click do botão btnExibeUltimoArquivoGerado o seguinte código:
Private Sub btnExibeUltimoArquivoGerado_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExibeUltimoArquivoGerado.Click 'limpa os listbox lstDados.Items.Clear() lstFormatado.Items.Clear() Try 'verifica se existe o arquivo de destino formatado If File.Exists(nomeArquivoDestino) = True Then Dim Tr As IO.TextReader = System.IO.File.OpenText(nomeArquivoDestino) Dim FileLines() As String = Split(Tr.ReadToEnd(), vbCrLf) Tr.Close() 'exibe o arquivo formatado no listbox For i = 0 To FileLines.Length - 1 lstFormatado.Items.Add(FileLines(i)) Next Else MsgBox("arquivo não existe") End If Catch ex As Exception MsgBox("Ocorreu um erro durante a exibição do arquivo : " & ex.Message) End Try End Sub |
No evento Click do botão btnApagarArquivoGerado temos o código que exclui o último arquivo de destino gerado:
Private Sub btnApagarArquivoGerado_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnApagarArquivoGerado.Click Try 'verifica se o arquivo existe If File.Exists(nomeArquivoDestino) = True Then lstFormatado.Items.Clear() 'apaga o arquivo File.Delete(nomeArquivoDestino) MsgBox("arquivo excluido") End If Catch ex As Exception MsgBox("Ocorreu um erro durante a exclusão do arquivo : " & ex.Message) End Try End Sub |
O objetivo foi mostrar como usar as classes do namespace System.IO para realizar uma tarefa prática. Eu não usei um projeto Windows Forms onde coloquei o código no próprio formulário mas você deve atentar que essa prática não é aderente as boas práticas.
Deixo como exercício a separação da lógica de negócio em uma camada separada da camada de apresentação de forma a tornar o projeto mais fácil de manter e testar.
Pegue o projeto completo aqui : Gerar_Arquivo_Texto.zip
Obs: Como exemplo eu deixei uma rotina comentada no projeto que utiliza o StringBuilder no tratamento de strings.
Eu sei é apenas VB .NET mas eu gosto...
"Graças e Paz da parte de Deus Pai e da
de nosso Senhor Jesus Cristo. O qual se deu a si mesmo por nossos pecados para
nos livrar do presente século mau, segundo a vontade de Deus nosso Pai, ao qual
glória para todo o sempre, Amém."
Gálatas 3-5
Referências: