Como tratar Arquivos textos com o Visual Basic


Atendendo a diversos pedidos ( 2 e-mail's , :-)))) ) estarei abordando o assunto de como tratar arquivos textos no Visual Basic . Aqui leia-se acessar , importar e exportar arquivos no formato texto - delimitado e largura fixa. 

A teoria ( se é que podemos chamar isto de teoria...)

Basicamente , existem dois tipos de arquivos textos :os tratáveis e os intratáveis.... 

Brincadeiras a parte podemos didaticamente classificar os arquivos textos em dois tipos: os de largura fixa e os delimitados.

Delimitados

Os arquivos textos delimitados possuem um caractere especial para separar os campos. A seguir temos um exemplo de  um arquivo texto delimitado:

1;Maria da Silva;Portugues;7;3
200;Jaime Rui LIma;Matematica;9;1
30;Jose Bueno Dias;Quimica;5;4

O layout deste arquivo  indica que existem 5 campos(colunas) com as seguintes características:

Campo1 - Numérico - Tamanho 3     -> Código
Campo2 - Texto     - Tamanho 15    -> Nome do Aluno
Campo3 - Texto     - Tamanho 10    -> Disciplina
Campo4 - Numérico - Tamanho 1     -> Nota 
Campo5 - Numérico - Tamanho 1     -> Faltas

O delimitador usado entre os campos é o ponto e vírgula (;), mas poderia ser a vírgula (,) ou outro caractere válido. ( * , ! , etc.)

Largura Fixa

O mesmo arquivo acima no formato de largura fixa  teria o seguinte layout:

001Maria da SilvaPortuguês73
200Jaime Rui LImaMatematica91
030Jose Bueno DiasQuimica54

Como podemos acessar este arquivo ??? Bem , ao trabalho...

1 - Acessando um arquivo texto

Vamos supor que o arquivo esteja no formato delimitado , com o nome alunos.txt e que esteja no diretório c:\dados. Você sabe o nome , a localização e o formato do arquivo texto. Com essas informações já podemos montar nossa estratégia de como acessar o bendito arquivo:

a-) Usando a DAO e os controles vinculados

Não fique triste , vamos mostrar como acessar este arquivo usando o Data Control depois mostraremos como fazer o serviço via código.

Ao final o seu formulário deverá ter o seguinte jeitão:

Agora para cada controle textbox - defina as propriedades :DataSource e DataField como abaixo:

DataSource =  Data1

DataField = Codigo      

Repita a operação para cada caixa de texto e altere a propriedade DataField na seguinte sequência: Nome, Materia, Nota e Faltas.

Agora rode o projeto. Se você fez tudo certo vai obter o seguinte resultado:

Pronto !!! você acabou de acessar um arquivo texto sem usar uma única linha de código. O comportamento do arquivo será idêntico se usarmos um arquivo de largura fixa e,  é idêntico ao que você tem quando acessa uma tabela....

"Como ele fez isto ????" - Se você ainda não se fez essa pergunta deveria esta fazendo... Então deixa que eu pergunto: - "Como o VB sabe os campos que tem que vincular ??? "  , "Como o VB sabe os tipos dos campos dentro do meu arquivo texto ??? " , Como ??? Como ???? 

Compreendendo o arquivo Schema.ini

Existe um arquivo chamado Schema.ini que o Visual Basic utiliza para saber o lay-out de um arquivo texto ao acessá-lo. O arquivo Schema.ini possui uma estrutura que fornece informações sobre os registros de um arquivo texto, são elas: 

  1. O nome do arquivo texto
  2. O formato do arquivo
  3. Os nomes das colunas (campos)
  4. A largura e o tipo do dado
  5. O conjunto de caracteres usados
  6. Tipos especiais de conversão

O arquivo SCHEMA.INI usado para o nosso exemplo mostrado acima  tem a seguinte estrutura:

[ALUNOS.TXT]
ColNameHeader = False
Format = Delimited(;)
CharacterSet = ANSI
Col1=codigo Integer width 3
Col2=nome Char width 40
Col3=materia Char width 30
Col4=nota Integer width 2
Col5=faltas Integer width 2

Vejamos a seguir um apanhado geral sobre cada entrada de um arquivo Schema.ini:

1-) A primeira entrada de um arquivo Schema.ini informa sempre o nome do arquivo texto fonte escrito entre colchetes ([]). Assim para o nosso caso , como queriamos acessar o arquivo ALUNOS.TXT temos:

[ALUNOS.TXT]

2-) A entrada Format do arquivo especifica o formato do arquivo texto. O driver para texto IISAM pode ler o formato automaticamente da maioria dos arquivos no formato delimitado. Você pode usar qualquer caractere como um delimitador em um arquivo texto exceto a dupla aspas ("). O valores válidos para a opção Format são:

Especificado de Formato  Formato da tabela
 
TabDelimited Os campos são delimitados por Tabs
CSVDelimited Os Campos são delimitados por vírgulas. (CSV - Comma Separated Values)
Delimited(*) Os campos são delimitados por asteristicos. O asteristico pode ser substituito por qualquer caractere. (exceto aspas duplas) 
FixedLength Os campos do arquivo são do foramato de largura fixa.

No nosso exemplo usamos como separador o ponto-e-vírgula (;) , então fizemos:

Format = Delimited(;)

Obs:  A entrada Format no arquivo Schema.ini sobrepõe a configuração Format do registro do Windows na chave: \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\3.5\Engines\Text 

3-) Podemos especificar o nome dos campos em um arquivo delimitado por caracteres de duas maneiras distintas:

a-) incluindo o nome dos campos na primeira linha da tabela e definindo a opção ColNameHeader no arquivo Schema.ini como True 

b-) especificando cada coluna pelo número e designando o nome da coluna e o tipo de dados.

Para arquivos no formato de largura fixa você precisa especificar cada coluna pelo número e designar o nome do campo seu tipo e largura.

Obs:  A opção ColNameHeader no arquivo  Schema.ini sobrepõe a configuração FirstRowHasNames do registro do windows.

Ao usar a opção ColNameHeader para definir os nomes dos campos em um arquivo delimitado, você instrui o JET a considerar os tipos de dados dos campos. Para indicar quantas colunas o Microsoft Jet irá procurar quando considerar os tipos dos campos use a opção MaxScanRows. Se você definir MaxScanRows igual zero o Microsoft Jet irá procurar no arquivo inteiro.

O seguinte exemplo indica que o Jet irá usar os dados da primeira linha da tabela do arquivo para determinar o nome dos campos e irá examinar o arquivo inteiro para determinar o tipo de dados usado:

ColNameHeader=True
MaxScanRows=0

A seguir um exemplo de como designar os campos da tabela usando o número da coluna (opcional para arquivos delimitados). Nele temos os campos usados em nosso exemplo:

Col1=codigo Integer width 3
Col2=nome Char width 40
Col3=materia Char width 30
Col4=nota Integer width 2
Col5=faltas Integer width 2

A sintaxe usada é a seguinte:   Coln=nomedocampo tipodocampo [Width #]

A tabela abaixo descreve cada parte usada para definir um campo:

Argumento Descrição
nomedocampo O nome da coluna
tipodocampo Tipos válidos:

Microsoft Jet:

Bit (Boolean)
Byte
Short (Integer)
Long
Currency
Single
Double
Date/Time
Text
Memo

Driver ODBC Texto:

Char (mesmo que Text)
Float (mesmo que Double)
Integer (mesmo que Short)
LongChar (mesmo que Memo)
Date date format

Width(Largura) A palavra Width.(opcional para arquivos delimitados)
# Um valor inteiro que define a largura da coluna

4-) Você pode selecionar dois conjuntos de caracteres: ANSI e OEM.

5-) O arquivo  Schema.ini contém um número de opções que você pode usar para definir como os dados serão convertidos ou exibidos quando lidos de um arquivo texto pelo Microsoft Jet. A seguir algumas opções:

Opção Descrição
 
DateTimeFormat Pode ser definida para formatar uma string indicando datas e horas. Todos os formatos do Jet são suportados exceto AM e PM. Se for omitida o formato usado será as opções  de data abreviada e tempo  do Painel de controle do Windows.
DecimalSymbol Pode ser usado qualquer caractere  que é utilizado para separar a parte inteira da fracionária de um número.
NumberDigits Indica o número de dígitos decimais na porção fracionária de um número.
CurrencySymbol Indica o símbolo usada para valores monetários no arquivo texto.

Bem , creio que deu para enjoar da teoria. Antes de terminar um detalhe: o arquivo Schema.ini tem que estar no mesmo diretório do arquivo que você quer acessar.

Para ilustrar vamos criar dois arquivos SCHEMA.INI um para um arquivo texto delimitado e outro para um de largura fixa. Suponha que temos os seguintes arquivos para acessar:

1- Arquivo texto delimitado: MATERIAS.TXT

1;MATEMATICA
2;QUIMICA
3;PORTUGUES
4;FISICA

Um arquivo SCHEMA.INI para este caso poderia  ser o seguinte:

[MATERIAS.TXT]
ColNameHeader=True
Format=Delimited(;)
MaxScanRows=0
CharacterSet=OEM
Col1=Codigo Integer Width 1
Col2=Disciplina Char Width 30

2- Arquivo texto de largura fixa: MATERIAS.TXT

1MATEMATICA
2QUIMICA
3PORTUGUES
4FISICA

Um arquivo SCHEMA.INI para este caso poderia ser o seguinte:

[MATERIAS.TXT]
ColNameHeader=False
Format=FixedLenght
MaxScanRows=30
CharacterSet=OEM
Col1=Codigo Integer Width 1
Col2=Disciplina Char Width 30

Importando um arquivo texto via código (Importando um arquivo texto para uma tabela )

Vamos supor que você tem um arquivo texto e que precisa importar este arquivo para um banco de dados access gerando uma tabela com os dados do arquivo texto.  É claro que você pode fazer isto diretamente usando o Access ou outra ferramenta , mas se você não tiver nada disto a sua disposição só lhe sobrará uma alternativa : fazer a importação via código.

O VB lhe oferece algumas alternativas de como fazer este trabalho via código. Você pode usar as funções de arquivo clássicas do VB ( Open, Input, Close, ...) ; pode usar também a Microsoft Scripting Runtime Library (objetos FileSystem e TextStream)   

A primeira coisa que você tem que saber é qual o jeitão do arquivo texto, ou seja, qual a ordenação dos dados presentes no arquivo texto. Os dados podem estar no formato delimitado ou no de largura fixa. Você precisa então montar a estrutura da tabela que deseja criar a partir dos dados do arquivo texto.

Vamos supor que você tenha que tratar um arquivo com os dados dos clientes de sua empresa chamado Clientes.txt  , e , que este arquivo contenha as seguintes informações: codigo, nome,endereco, telefone,data de nascimento . Ao abrir o arquivo texto você deparou com a seguinte estrutura: 

1001Maria da Silva RochaRua XV de Novembro 1000119903000112051945
1002Joao Lima Bueno     Rua da Abolicao 12           119243159807061955
1003Carlos Ramirez        Rua 25 de Janeiro 12        110255313402031960
1004Samanta Cinceniti   Rua Mirassol 234              110224232101071970
1005Marcos Barbosa      Rua dos Girassois 12         110356560810081980
1006Felipe Xavier Silva   Av Sao Luis 102               119780882205111940
1007Jaime Andrade        Av Pernambuco 98            119911105425011985
1008Cintia Lima Se        Rua Bahia 11                    110218093319121950

Analisando o arquivo chegamos a seguinte conclusão quanto as posições dos campos que deverão ser importados para a nossa tabela no banco de dados:

Código         -> posição 1 a 4            =>   4 posições
Nome           -> posição 5 a 24         =>  20 posições    
Endereço     -> posição 25 a 47       =>  23 posições
Telefone      -> posição 48 a 58       =>  10 posições
Nascimento -> posição 59 a 65       =>   8  posições

Agora vamos ao projeto com o código que fará  o serviço de importação dos dados:

1-) Crie um novo projeto no Visual Basic , pode chamá-lo clientes

2-) No formulário padrão insira duas caixas de texto e duas labels. Uma caixa de texto deverá servir para informar o nome do arquivo texto a importar a outra para informar o nome da base de dados para qual iremos importar o arquivo

3-) Insira um botão de comando com a propriedade caption definida como : "Importar arquivo texto"

4-) Insira o seguinte código no evento click do botão de comando:

Private Sub Command1_Click()

Dim F As Long, Linha As String
Dim db As Database, rs As Recordset

F = FreeFile
Open txttexto.Text For Input As F   'abre o arquivo texto
Set db = DBEngine(0).OpenDatabase(txtbase.Text)   'abre o banco de dados

On Error Resume Next    'se a tabela não existir escapa da mensagem de erro

db.Execute "DROP TABLE Clientes"   'exclui a tabela se ela ja existir

On Error GoTo trata_erro   'ativa tratamento de erros

db.Execute "CREATE TABLE Clientes (ID LONG, [Nome] TEXT (50), " _
& "[Endereco] TEXT (50), [telefone] TEXT (15), [Nascimento] TEXT (10))" 'cria a tabela c/a estrutura 

Set rs = db.OpenRecordset("Clientes", dbOpenTable)   'abre a tabela para receber os dados

Do While Not EOF(F)
Line Input #F, Linha 'lê uma linha do arquivo texto

'extrai a informação do arquivo texto usando a função MID
codigo = Mid(Linha, 1, 4)
nome = Mid(Linha, 5, 20)
endereco = Mid(Linha, 25, 23)
telefone = Mid(Linha, 48, 10)
nascimento = Mid(Linha, 58, 8)

rs.AddNew  'inclui novo registro
rs(0) = codigo 
rs(1) = nome
rs(2) = endereco
rs(3) = telefone
rs(4) = nascimento
rs.Update    'grava o registro inserido
Loop

MsgBox "Arquivo texto importado com sucesso !! "

rs.Close
db.Close

Close #F
Exit Sub

trata_erro:
MsgBox Err.Description

End Sub

Observe que usamos a função MID do VB para , de acordo com a posição de inicio da coluna, extraírmos nossa informação. De lambuja vamos dar a sintaxe da  função:

MID - retorna um string do tipo Variant contendo o número especificado de caracteres em uma string

Sintaxe: Mid(string, inicio[,comprimento])

Parte Descrição
string Uma expressão caractere do qual iremos extrair um certo número de caracteres.
inicio Posição inicial a partir da qual iremos extrair uma certa quantidade de caracteres da expressão string.
comprimento Número de caracteres que desejamos extrair a partir da posição inicial . Se omitida todos os caracteres a partir de inicio serão extraidos.

Agora execute o projeto e pronto , nosso arquivo já foi importado e uma tabela já foi criada, vejamos a tabela clientes gerada:

Nada mal , não é mesmo ??? É claro que existem maneiras mais elegantes de fazer o serviço , como por exemplo: criar um classe para importação.

Gerando um arquivo texto com os dados de uma tabela

Vamos agora realizar o processo inverso : exportar os dados de uma tabela para um arquivo texto. O processo é muito simples. Iremos mostrar dois exemplos : um usando as funções clássicas do VB e o outro usando o objeto FileSystem.

1- Exportando um conjunto de registros vai objeto TextStream

Neste exemplo iremos usar a tabela Authors do banco de dados Biblio.mdb. Nosso objetivo será exportar para um arquivo texto os registros da tabela Authors. Recomendo que você renomeie o seu arquivo Biblio.mdb original para evitar estragos...:-) Vamos lá...

a-) Inicie um  novo projeto no VB e no formulário padrão insira os seguintes controles:

- Duas caixas de texto ,  dois controles  e um botão de comando . Veja figura abaixo:

b-) Faça a referência a DAO 3.6 , se estiver usando o access 2000 , ou DAO 3.51 para versões anteriores, no seu projeto. 

c-) Na seção General Declarations do formulário definas as variáveis objeto:

Dim db As Database
Dim rs As Recordset

d-) Insira o seguinte código no evento click do botão de comando:

Private Sub Command1_Click()
Dim registros As Integer

On Error GoTo trata_erro

Set db = opendatabase(Text1.Text)
Set rs = db.openrecordset("Authors")

rs.MoveLast
rs.MoveFirst
registros = rs.RecordCount

Open Text2.Text For Output As #1

Do Until rs.EOF
Print #1, rs!Au_Id & " " & rs!Author & " " & rs![year born]
rs.movenext
Loop

Close #1
rs.close


MsgBox "Foram exportados " & registros & " para o arquivo texto"

Exit Sub

trata_erro:
MsgBox Err.Description

End Sub

Explicando passo a passo: 

  1. Definimos as variáveis objeto : 
  2. Ativamos o tratamento de erro - On Error GoTo trata_erro
  3. A seguir abrimos o banco de dados - Set db = opendatabase(Text1.Text)
  4. Abrimos o recordset usando a tabela Authors - Set rs = db.openrecordset("Authors")
  5. Fazemos a movimentação do ponteiro no arquivo para sabermos quantos registros temos na tabela. rs.MoveLast
    rs.MoveFirst
  6. Atribuimos a quantidade de registros á variável registros. - registros = rs.RecordCount
  7. Abrimos o arquivo texto Autores.txt para receber os dados. (Se o arquivo não existir ele é criado) - Open Text2.Text For Output As #1
  8. Percorremos a tabela do primeiro até o seu final e gravamos os campos : Au_Id, Authors e Year Born no arquivo texto usando o comando Print #1 .( Os dados são separados por um espaço - " ")           Do Until rs.EOF
    Print #1, rs!Au_Id & " " & rs!Author & " " & rs![year born]
    rs.movenext
    Loop

Obs:A formatação da saída pode ser feita usando diversas opções , como por exemplo:

        Spc(n) - insere um número fixo de espaços

        Tab(n) - insere o texto em um ponto fixo na linha

        (;) - Não quebra a linha após a expressão da impressão

        Ex:  Print #1, rs!Au_Id ;  spc(1) ;  rs!Author

  1. Fechamos os arquivos e informamos quantos registros foram exportados. 

    Close #1
    rs.close

    MsgBox "Foram exportados " & registros & " para o arquivo texto"

Se você fez tudo certo , após executar o projeto deverá obter a seguinte tela:

Dando uma de curioso e abrindo o arquivo Autores.txt gerado , iremos obter:

No arquivo podemos distinguir : o codigo do autor ( Au_Id) ,  o nome do autor ( Authors) e a data de nascimento (Year Born) separador por um espaço. É claro que só  mostramos uma parte do arquivo. 

2- Exportando um conjunto de registros vai objeto FileSystemObject : criando um arquivo delimitado

A versão 6.0 do VB trouxe como novidade a Microsoft Scripting Runtime Library , com ela podemos evitar os antigos comandos para tratamento de arquivos , pois podemos exportar os dados de forma clara e baseada em objetos. Como queremos exportados dados iremos focar somente os objetos FileSystemObject e TextStream . Vejamos então como criar um projeto para exportar os dados da tabela Authors do banco de dados Biblio.mdb no formato delimitado:

  1. a-) Inicie um  novo projeto no VB e no formulário padrão insira os seguintes controles:

    - Duas caixas de texto ,  dois controles  e um botão de comando . Veja figura abaixo: (idêntica ao formulário do projeto anterior , aliás você pode incluir o formulário neste novo projeto.)

    b-) Faça a referência a DAO 3.6 , se estiver usando o access 2000 , ou DAO 3.51 para versões anteriores, no seu projeto. 

    c-) Faça a referência a Microsoft Scripting Runtime no seu projeto. Veja abaixo:

    d-) Na seção General Declarations do formulário definas as variáveis objeto:

    Dim db As Database
    Dim rs As Recordset

    e-) Insira o seguinte código no evento click do botão de comando:

Private Sub Command1_Click()

'define variáveis
Dim fs As Scripting.FileSystemObject
Dim texto As Scripting.TextStream
Dim sql As String
Dim contador As Long

'monta consulta sql selecionando o codigo e nome do autor
'para codigos menores que 200
sql = "Select Au_Id , Author FROM Authors "
sql = sql & " Where Au_Id < 200 "

'abre o banco de dados e o recordset
Set db = opendatabase(Text1.Text)
Set rs = db.openrecordset(sql)

'cria um objeto filesystemobject
Set fs = New Scripting.FileSystemObject
Set texto = fs.OpenTextFile(Text2.Text, ForWriting, True)

'Percorre o recordset até o seu final exportando os dados selecionados
Do Until rs.EOF
  texto.Write rs!Au_Id & ";" & rs!Author & vbCrLf

  'atualiza contador
  contador = contador + 1
  rs.MoveNext

Loop

'Fecha os objetos e libera variáveis

texto.Close
Set texto = Nothing
Set fs = Nothing
rs.Close
Set rs = Nothing

MsgBox "Total de Registros Exportados : " & contador

End Sub

Observe que usamos o ponto e vírgula(;)  como delimitador entre os campos do arquivo. Após executar a aplicação devemos obter o seguinte arquivo texto.

 Chegamos a fim da linha. Até o próximo artigo...:-)