Trabalhando com arquivos sequenciais
Há vezes que precisamos trabalhar com arquivos com formatos
diferentes daqueles com que o Excel trabalha e nem sempre é um formato fácil de
importar. Normalmente são usados arquivos sequenciais, ou seja, arquivos em que
cada linha representa um registro e que são processados do início até o fim, em
sequência.
Se o arquivo for recebido apenas uma vez, não há muito
problema em fazer a importação de maneira manual. Porém, quando é um arquivo
recebido rotineiramente, é melhor automatizar a importação do arquivo. E o que
é melhor, pode-se automatizar também toda a formatação da tabela feita após a
importação.
Por outro lado, pode haver a necessidade de gerar um arquivo
em um formato específico. Neste caso, a criação manual do arquivo pode ser
demasiadamente trabalhosa, por isso é melhor fazer um processo automático para
não dar margem para erros na criação do arquivo, principalmente se houver
muitas linhas e colunas para serem exportadas.
O código para ler ou gravar um arquivo não é difícil. O
esqueleto básico para arquivos sequenciais é o seguinte: abrir arquivo, laço
para processar, fechar arquivo. A complexidade está no processamento do
registro, seja para ler ou para gravar o registro. Vejamos o código para ler um
arquivo:
Sub ProcessarArquivo()
Dim Arquivo As String
Dim Registro As String
Arquivo =
"C:\Temp\Teste.txt"
Open Arquivo For Input
As #1
Do Until EOF(1)
' Lê o próximo
registro
Line Input #1,
Registro
' Chama a sub-rotina para processar o
registro lido
ProcessarRegistro
(Registro)
Loop
Close #1
End Sub
Vamos entender esse código. No início ele cria uma variável
de formato texto chamada Arquivo, à
qual é associado um arquivo. Note bem que o caminho do arquivo está completo,
com disco e pasta especificados, caso contrário o Excel pode não encontrar o
arquivo e então gerará uma mensagem de erro.
É possível obter o arquivo por meio de uma caixa de diálogo,
onde o usuário pode selecionar o arquivo. Neste caso deve-se alterar a linha
para a seguinte forma:
Arquivo = Application.GetOpenFilename(FileFilter:="Arquivo
de texto (*.txt), *.txt", _
title:="Selecione
um arquivo de texto para importar")
Use a forma que for mais adequada à necessidade. Se o
arquivo vem sempre com o mesmo nome e caminho, a primeira forma é a melhor.
Caso o nome e o caminho possam variar, a segunda forma ajuda a selecionar o
arquivo.
Continuando o código, logo a seguir aparece um comando Open, que irá abrir o arquivo. Ele
contém o parâmetro For Input, que
indica que o arquivo será usado para leitura (outros parâmetros serão vistos
mais adiante). A seguir, há outro parâmetro, As #1, que indica que o número de ordem do arquivo que está sendo
aberto. Se houver outros arquivos a serem abertos ao mesmo tempo, deve-se
incrementar o número: #2, #3 etc, sendo que o limite é 511. Como pode-se imaginar,
trabalhar com mais de um arquivo ao mesmo tempo requer cuidado. Aqui vou
limitar a um arquivo para facilitar o aprendizado.
Após o arquivo ser aberto, há uma estrutura de repetição Do Until... Loop, que testa uma condição
EOF(1). EOF significa end of file,
ou seja, fim do arquivo, e 1 é o
número de ordem do arquivo. Traduzindo, o laço será processado até que não haja
mais registros a serem lidos.
Dentro do laço, temos uma o comando Line Input #1, Registro, que irá preencher a variável Registro com o conteúdo do registro lido
no arquivo. Há também uma chamada para uma sub-rotina chamada ProcessarRegistro, que irá processar o registro,
onde estará toda a lógica e complexidade do que fazer com o registro lido.
Por fim, temos o comando Close
#1, que irá fechar o arquivo. Lembre-se sempre de fechar os arquivos após processar,
caso contrário eles podem ficar presos ao Excel até que este seja fechado,
impedindo outros programas ou outras pessoas de usarem o arquivo.
Agora vejamos o código para fechar o arquivo:
Sub ProcessarArquivo()
Dim Arquivo As String
Dim Registro As String
Dim Linha As Integer
Dim UltimaLinha As Integer
Arquivo =
"C:\Temp\Teste.txt"
Open Arquivo For
Output As #1
UltimaLinha = Cells(1,
1).End(xlDown).Row
For Linha = 2 To
UltimaLinha
' Chama a
sub-rotina para gerar registro para gravação
Registro = GerarRegistro(Linha)
' Grava o registro
no arquivo
Print #1, Registro
Next
Close #1
End Sub
Aqui temos três diferenças em relação ao código de abrir
arquivo. A primeira é que o comando Open
agora está com o parâmetro For Output,
o que significa que o arquivo será usado para gravação. A segunda diferença é o
laço de repetição, que agora se refere à planilha, que é de onde sairão os
dados para serem gravados no arquivo. Aqui usei um laço For... Next, mas poderia ser qualquer outra estrutura de repetição. E a
terceira é o comando Print #1, Registro,
que irá gravar o conteúdo da variável Registro
no arquivo 1. Há o comando Write, que é usado da mesma forma, porém
este grava strings entre aspas.
Observe nos códigos uma diferença importante nos laços: na
leitura, primeiro lê o registro e depois processa; na gravação, primeiro gera o
registro e depois grava. É algo bem lógico, mas às vezes uma desatenção nesse
detalhe pode causar a perda de registros.
O conhecimento até agora permite ler e gravar arquivos para
muitos casos. Daqui em diante, vamos aprofundar o conhecimento no assunto,
estudando alguns detalhes mais a fundo.
O comando Open tem
a seguinte sintaxe (os parâmetros opcionais estão entre colchetes):
Open NomeDoArquivo For
Modo [Access Acesso] [Trava] As Número [Len=Comprimento]
Vimos os modos Input
e Output acima. Tem ainda os
seguintes modos:
- Append: Adiciona
registros a um arquivo existente;
- Binary: Usado
para ler e gravar arquivos em formato binário;
- Random: Para
arquivos com acesso aleatório (não sequencial). É a opção padrão.
Os modos Random e Binary não serão
abordados neste artigo devido à complexidade. Eles terão um artigo no futuro.
O parâmetro opcional Access pode ter os seguintes valores:
- Read: Permite
somente leitura;
- Write: Permite
somente escrita;
- Read Write:
Permite tanto leitura quanto escrita.
Perceba que não há necessidade deste parâmetro quando se usa
os modos Input, Output e Append, somente
nos casos de modos Binary e Random.
Trava define se o
arquivo pode ser aberto por outro processo enquanto estiver aberto no Excel. Os
parâmetros possíveis são:
- Shared:
Compartilhado, permite leitura e escrita;
- Lock Read: Não
permite leitura, só escrita;
- Lock Write: Não
permite escrita, só leitura;
- Lock Read Write:
Não permite leitura nem escrita.
Por fim, Len
define o comprimento do registro. Não há necessidade de especificar e é mais
vantajoso controlar o comprimento do registro na própria criação, definindo com
campos de tamanhos fixos.
Agora vejamos a diferença entre os comandos Print e Write com um código simples:
Sub GravarTexto()
Dim Arquivo As String
Arquivo = "C:\Temp\Texto
Gravado.txt"
Open Arquivo For
Output As #1
Print #1, "Olá,
mundo!"
Write #1, "Olá,
mundo!"
Close #1
End Sub
O resultado do arquivo gravado é o seguinte:
Olá, mundo!
"Olá, mundo!"
Desta forma é mais fácil visualizar a diferença entre os
dois comandos. Enquanto Print apenas
gravou o conteúdo do texto, Write
deixou-o entre aspas.
É possível adicionar mais argumentos em ambos comandos,
separando por vírgulas. Desta forma podemos gravar vários campos ou variáveis em
uma linha sem precisar compor um campo com o registro inteiro. Porém, há
diferenças na forma de gravar as linhas. Altere as linhas dos comandos Print e Write da seguinte forma:
Print #1, "Olá,
mundo!", 123
Write #1, "Olá,
mundo!", 123
Acrescentamos um valor numérico, que será gravado ao lado da
string. Observe como fica a gravação:
Olá, mundo! 123
"Olá, mundo!",123
O comando Print
separa campos distintos com uma tabulação, enquanto o Write separa com vírgulas. Perceba que o valor numérico não recebeu
aspas. Se fosse outro campo do tipo string,
o texto seria envolvido por aspas.
Repare também que a string
gravada contém uma vírgula. Ela não vai interferir no registro, pois no
registro gravado com Print não há
separação por vírgulas, enquanto no registro gravado com Write ela está entre aspas. É importante conhecer esses detalhes
para saber decidir como os dados serão gravados, porque a forma de ler depende
diretamente dessa escolha.
Para a leitura dos dados, pode-se ler o registro inteiro e depois
usar um comando como o Instr para
localizar os separadores, seja a tabulação ou a vírgula, e então ir compondo as
células com os valores. Há uma alternativa mais prática que usa o comando Split, que gera um array com os dados do
registro. Observe o código abaixo:
Sub LerTexto()
Dim Arquivo As String
Dim Registro As String
Dim Linha As Integer
Dim Conteudo As
Variant
Dim Contador As
Integer
Arquivo =
"C:\Temp\Texto Gravado.txt"
Linha = 1
Open Arquivo For Input
As #1
Do Until EOF(1)
Line Input #1,
Registro
Conteudo =
Split(Registro, vbTab)
For Contador =
LBound(Conteudo) To UBound(Conteudo)
Cells(Linha,
Contador + 1).Value = Conteudo(Contador)
Next
Linha = Linha + 1
Loop
Close #1
End Sub
Analisando o código: o comando Line Input irá ler o registro e gravá-lo na variável Registro, como visto anteriormente. A
linha seguinte compõe a variável Conteudo
como um array, separando os itens
pelo separador. O caractere da tabulação é identificado pela constante do VBA vbTab. Por fim, há um laço For... Next que irá preencher as células
da planilha ativa com os valores do array
Conteudo. Atente para o fato de que
um array inicializa sempre em 0, por
isso é preciso acrescentar 1 para gravar na primeira coluna.
Experimente criar um arquivo com várias linhas e vários
valores em cada linha, separados por tabulações e então teste o código. Depois
experimente fazer o mesmo, separando por vírgulas, colocando strings entre
aspas, alterando o vbTab no código
para "," (a fim de indicar
que é para separar pelas vírgulas) e teste novamente. Se você manteve a string "Olá, mundo!" do exemplo anterior, verá que na separação
por vírgulas uma célula ficou com "Olá
e a outra ficou com mundo!".
Outro problema é que as strings
permaneceram com as aspas nas células. São problemas que demandarão um código
adicional para verificar essas eventualidades e corrigi-las todas.
Particularmente prefiro criar uma variável para compor o
registro, mantendo todos os campos de tamanho fixo, para então gravar o
registro. Em uma das vídeo-aulas do Alessandro Trovato foi demonstrado uma
forma de como fazer isso, reveja se for necessário.
Por fim, algumas dicas para quando estiver exportando dados
para arquivos:
- Números com casas decimais devem ser exportados de
preferência sem a vírgula. Se for valor de moeda (duas casas decimais),
multiplique por 100 antes de exportar e divida por 100 quando for importar. Caso
sejam valores com mais casas decimais, defina o multiplicador de acordo com o valor da maior casa decimal para então
exportar todos com o mesmo valor. Isso é para ajudar a manter os números com a
mesma quantidade de dígitos e assim facilitar a exportação e posterior
importação dos valores;
- Transforme as datas para o formato AAAA/MM/DD antes de
exportar, porque o Excel tem um problema na importação de datas. Ele considera
como MM/DD/AAAA a não ser que o MM seja maior que 12, neste caso ele importa
como DD/MM/AAAA. Imagine uma situação com muitas datas e o Excel bagunçando
tudo. Veja o resultado dos testes nas imagens abaixo:
Datas exportadas como DD/MM/AAAA: As datas de 01/02/2001 a 12/02/2001 foram importadas de maneira errada pelo Excel, enquanto o restante foi importado corretamente.
Datas exportadas como AAAA/MM/DD: Todas as datas foram importadas corretamente.
Espero que este artigo lhe ajude a trabalhar com arquivos de forma satisfatória e sem problemas. Quaisquer dúvidas, use a seção de comentários abaixo.
Pedro Martins
Formado em Tecnologia em Eletrônica Digital, já trabalhou como artefinalista, eletrotécnico, programador de CLP (para máquinas industriais) e analista de sistemas em sistema bancário, programando em COBOL.
Mexe com computadores e programação desde a segunda metade dos anos 1980, quando teve um MSX e aprendeu a programar em BASIC. É a favor da disseminação do conhecimento.
Nenhum comentário