4. Classes .NET de uso comum
Apresentamos aqui algumas classes da plataforma .NET que são de interesse, mesmo para um principiante. Mostramos, em primeiro lugar, como obter informações sobre as centenas de classes disponíveis.
4.1. Procurar ajuda com SDK.NET
4.1.1. wincv
Se tiver instalado apenas o SDK e não o Visual Studio.NET, poderá utilizar o programa wincv.exe, que se encontra normalmente na estrutura de diretórios do SDK, por exemplo, C:\Program Files\Microsoft Visual Studio.NET 2003\SDK\v1.1. Ao iniciar este utilitário, é apresentada a seguinte interface:
![]() |
Digita-se em (1) o nome da classe pretendida. Isto apresenta em (2) vários temas possíveis. Escolhe-se o que for adequado e obtém-se o resultado em (3), neste caso a classe HashTable. Este método é adequado se se souber o nome da classe que se procura. Se se quiser explorar a lista de possibilidades oferecidas pela plataforma .NET, poderá utilizar o ficheiro HTML StartHere.htm, que também se encontra diretamente na pasta de instalação do SSK.Net, por exemplo, C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.

A ligação «.NET Framework SDK Documentação» é a que deve seguir para obter uma visão geral das classes «.NET»:

Aqui, seguiremos o link [Bibliothèque de classes]. Nele encontra-se a lista de todas as classes de .NET:

Vamos seguir, por exemplo, o link System.Collections. Este espaço de nomes agrupa várias classes que implementam coleções, entre as quais a classe HashTable:

Vamos seguir o link HashTable abaixo:

Obtemos a seguinte página:

Repare na posição do cursor abaixo. Este aponta para um link que permite especificar a linguagem pretendida, neste caso, o Visual Basic.
Aí encontramos o protótipo da classe, bem como exemplos de utilização. Sigamos o link [Hashtable, membres] abaixo:

Obtenha-se a descrição completa da classe:

Este método é o melhor para explorar o SDK e as suas classes. A ferramenta WinCV revela-se útil quando já se conhece um pouco a classe e se esqueceram alguns dos seus membros. O WinCV permite, então, localizar rapidamente a classe e os seus membros.
4.2. Procurar ajuda sobre as classes com o VS.NET
Apresentamos aqui algumas orientações para encontrar ajuda com o Visual Studio.NET
4.2.1. Opção «Ajuda»
Selecione a opção [?] no menu.

Aparece a seguinte janela:

Na lista suspensa, é possível selecionar um filtro de ajuda. Neste caso, selecionaremos o filtro [Visual Basic].

Há duas ajudas úteis:
- a ajuda sobre a própria linguagem VB.NET (sintaxe)
- a ajuda sobre os classes.NET que podem ser utilizados pela linguagem VB.NET
A ajuda sobre a linguagem VB.NET está acessível através de [Visual Studio.NET/Visual Basic et Visual C#/Reference/Visual Basic]:

É apresentada a seguinte página de ajuda:

A partir daí, as diferentes subsecções permitem-nos obter ajuda sobre diversos temas do VB.NET. Deve-se prestar atenção aos tutoriais do VB.NET:

Para aceder às diferentes classes da plataforma .NET, devemos selecionar a ajuda [Visual Studio.NET/.NET Framework].

Destacamos, em particular, a secção [Référence/Bibliothèque de classes]:

Suponhamos que estamos interessados na classe [ArrayList]. Esta encontra-se no espaço de nomes [System.Collections]. É importante saber isto; caso contrário, será preferível utilizar o método de pesquisa descrito a seguir. Obtém-se a seguinte ajuda:

A ligação [ArrayList, classe] apresenta uma visão geral da classe:

Este tipo de página existe para todas as classes. Apresenta um resumo da classe com exemplos. Para uma descrição dos membros da classe, siga o link [ArrayList, membres]:

4.2.2. Ajuda/Índice

A opção [Aide/index] permite procurar uma ajuda mais específica do que a anterior. Basta digitar a palavra-chave procurada:

A vantagem deste método em relação ao anterior é que não é necessário saber onde se encontra o que se procura no sistema de ajuda. Este é provavelmente o método a preferir quando se faz uma pesquisa específica, sendo o outro método mais adequado para descobrir tudo o que a ajuda tem para oferecer.
4.3. A classe String
A classe String apresenta inúmeras propriedades e métodos. Aqui estão alguns deles:
número de caracteres da cadeia | |
propriedade indexada por predefinição. [String].Chars(i) é o carácter n.º i da cadeia | |
retorna «verdadeiro» se a cadeia terminar com o valor | |
retorna verdadeiro se a cadeia começar por «value» | |
retorna verdadeiro se a cadeia for igual a value | |
retorna a primeira posição na cadeia de caracteres «value» — a pesquisa começa a partir do caractere n.º 0 | |
retorna a primeira posição na cadeia do valor «value» — a pesquisa começa a partir do caractere n.º startIndex | |
método de classe — devolve uma cadeia de caracteres, resultado da concatenação dos valores da matriz «value» com o separador «separator» | |
retorna uma cadeia de caracteres que é uma cópia da cadeia atual, na qual o caractere oldChar foi substituído pelo caractere newChar | |
a cadeia é considerada como uma sequência de campos separados pelos caracteres presentes na tabela separator. O resultado é a tabela desses campos | |
subcadeia da cadeia atual que começa na posição startIndex e tem length caracteres | |
converte a cadeia atual em minúsculas | |
converte a cadeia atual em maiúsculas | |
remove os espaços no início e no fim da cadeia atual |
Uma cadeia C pode ser considerada como uma matriz de caracteres. Assim,
- C.Chars(i) é o caractere i de C
- C.Length é o número de caracteres de C
Consideremos o seguinte exemplo:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Module test
Sub Main()
Dim uneChaine As String = "l'oiseau vole au-dessus des nuages"
affiche("uneChaine=" + uneChaine)
affiche("uneChaine.Length=" & uneChaine.Length)
affiche("chaine[10]=" + uneChaine.Chars(10))
affiche("uneChaine.IndexOf(""vole"")=" & uneChaine.IndexOf("vole"))
affiche("uneChaine.IndexOf(""x"")=" & uneChaine.IndexOf("x"))
affiche("uneChaine.LastIndexOf('a')=" & uneChaine.LastIndexOf("a"c))
affiche("uneChaine.LastIndexOf('x')=" & uneChaine.LastIndexOf("x"c))
affiche("uneChaine.Substring(4,7)=" + uneChaine.Substring(4, 7))
affiche("uneChaine.ToUpper()=" + uneChaine.ToUpper())
affiche("uneChaine.ToLower()=" + uneChaine.ToLower())
affiche("uneChaine.Replace('a','A')=" + uneChaine.Replace("a"c, "A"c))
Dim champs As String() = uneChaine.Split(Nothing)
Dim i As Integer
For i = 0 To champs.Length - 1
affiche("champs[" & i & "]=[" & champs(i) & "]")
Next i
affiche("Join("":"",champs)=" + System.String.Join(":", champs))
affiche("("" abc "").Trim()=[" + " abc ".Trim() + "]")
End Sub
' exibe
Sub affiche(ByVal msg As [String])
' exibe mensagem
Console.Out.WriteLine(msg)
End Sub
End Module
A execução produz os seguintes resultados:
dos>vbc string1.vb
dos>string1
uneChaine=l'oiseau vole au-dessus des nuages
uneChaine.Length=34
chaine[10]=o
uneChaine.IndexOf("vole")=9
uneChaine.IndexOf("x")=-1
uneChaine.LastIndexOf('a')=30
uneChaine.LastIndexOf('x')=-1
uneChaine.Substring(4,7)=seau vo
uneChaine.ToUpper()=L'OISEAU VOLE AU-DESSUS DES NUAGES
uneChaine.ToLower()=l'oiseau vole au-dessus des nuages
uneChaine.Replace('a','A')=l'oiseAu vole Au-dessus des nuAges
champs[0]=[l'oiseau]
champs[1]=[vole]
champs[2]=[au-dessus]
champs[3]=[des]
champs[4]=[nuages]
Join(":",champs)=l'oiseau:vole:au-dessus:des:nuages
(" abc ").Trim()=[abc]
Vejamos um novo exemplo:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Module string2
Sub Main()
' a linha a analisar
Dim ligne As String = "un:deux::trois:"
' os separadores de campos
Dim séparateurs() As Char = {":"c}
' divisão
Dim champs As String() = ligne.Split(séparateurs)
Dim i As Integer
For i = 0 To champs.Length - 1
Console.Out.WriteLine(("Champs[" & i & "]=" & champs(i)))
Next i
' junção
Console.Out.WriteLine(("join=[" + System.String.Join(":", champs) + "]"))
End Sub
End Module
e os resultados da execução:
O método Split da classe String permite colocar os campos de uma cadeia de caracteres numa matriz. A definição do método utilizado aqui é a seguinte:
matriz de caracteres. Estes caracteres representam os caracteres utilizados para separar os campos da cadeia de caracteres. Assim, se a cadeia for [champ1, champ2, champ3], poderá utilizar-se separator=new char() {","c}. Se o separador for uma sequência de espaços, utilizar-se-á separator=nothing. | |
matriz de cadeias de caracteres em que cada elemento é um campo da cadeia. |
O método Join é um método estático da classe String:
matriz de cadeias de caracteres | |
uma cadeia de caracteres que servirá de separador de campos | |
uma cadeia de caracteres formada pela concatenação dos elementos da tabela value, separados pela cadeia separator. |
4.4. A classe Array
A classe Array implementa um tabuleiro. No nosso exemplo, utilizaremos as seguintes propriedades e métodos:
propriedade - número de elementos da matriz | |
método de classe - devolve a posição de value na tabela ordenada array - procura a partir da posição index e com length elementos | |
método de classe - copia os elementos de length de sourceArray para destinationArray - destinationArray é criado para o efeito | |
método de classe - ordena a tabela array - esta deve conter um tipo de dados com uma função de ordenação por predefinição (cadeias de caracteres, números). |
O programa seguinte ilustra a utilização da classe Array:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Module test
Sub Main()
' leitura dos elementos de uma matriz introduzidos através do teclado
Dim terminé As [Boolean] = False
Dim i As Integer = 0
Dim éléments1 As Double() = Nothing
Dim éléments2 As Double() = Nothing
Dim élément As Double = 0
Dim réponse As String = Nothing
Dim erreur As [Boolean] = False
While Not terminé
' pergunta
Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
' leitura da resposta
réponse = Console.ReadLine().Trim()
' fim da introdução de dados se a cadeia estiver vazia
If réponse.Equals("") Then
Exit While
End If
' verificação da introdução
Try
élément = [Double].Parse(réponse)
erreur = False
Catch
Console.Error.WriteLine("Saisie incorrecte, recommencez")
erreur = True
End Try
' se não houver erros
If Not erreur Then
' nova tabela para receber o novo elemento
éléments2 = New Double(i) {}
' copia da tabela antiga para a nova tabela
If i <> 0 Then
Array.Copy(éléments1, éléments2, i)
End If
' a nova tabela passa a ser a tabela antiga
éléments1 = éléments2
' já não é necessário o novo tabelo
éléments2 = Nothing
' inserção de um novo elemento
éléments1(i) = élément
' mais um elemento na tabela
i += 1
End If
End While
' exibição da tabela não ordenada
System.Console.Out.WriteLine("Tableau non trié")
For i = 0 To éléments1.Length - 1
Console.Out.WriteLine(("éléments[" & i & "]=" & éléments1(i)))
Next i
' ordenação da tabela
System.Array.Sort(éléments1)
' exibição da tabela ordenada
System.Console.Out.WriteLine("Tableau trié")
For i = 0 To éléments1.Length - 1
Console.Out.WriteLine(("éléments[" & i & "]=" & éléments1(i)))
Next i
' Pesquisa
While Not terminé
' pergunta
Console.Out.Write("Elément cherché (rien pour arrêter) : ")
' leitura e verificação da resposta
réponse = Console.ReadLine().Trim()
' Concluído?
If réponse.Equals("") Then
Exit While
End If
' verificação
Try
élément = [Double].Parse(réponse)
erreur = False
Catch
Console.Error.WriteLine("Saisie incorrecte, recommencez")
erreur = True
End Try
' se não houver erros
If Not erreur Then
' procura-se o elemento na tabela ordenada
i = System.Array.BinarySearch(éléments1, 0, éléments1.Length, élément)
' Exibição da resposta
If i >= 0 Then
Console.Out.WriteLine(("Trouvé en position " & i))
Else
Console.Out.WriteLine("Pas dans le tableau")
End If
End If
End While
End Sub
End Module
Os resultados no ecrã são os seguintes:
Elément (réel) 0 du tableau (rien pour terminer) : 10,4
Elément (réel) 1 du tableau (rien pour terminer) : 5,2
Elément (réel) 2 du tableau (rien pour terminer) : 8,7
Elément (réel) 3 du tableau (rien pour terminer) : 3,6
Elément (réel) 4 du tableau (rien pour terminer) :
Tableau non trié
éléments[0]=10,4
éléments[1]=5,2
éléments[2]=8,7
éléments[3]=3,6
Tableau trié
éléments[0]=3,6
éléments[1]=5,2
éléments[2]=8,7
éléments[3]=10,4
Elément cherché (rien pour arrêter) : 8,7
Trouvé en position 2
Elément cherché (rien pour arrêter) : 11
Pas dans le tableau
Elément cherché (rien pour arrêter) : a
Saisie incorrecte, recommencez
Elément cherché (rien pour arrêter) :
A primeira parte do programa cria uma matriz a partir de dados numéricos introduzidos pelo teclado. A matriz não pode ser dimensionada antecipadamente, uma vez que não se sabe o número de elementos que o utilizador irá introduzir. Trabalha-se, portanto, com duas matrizes: éléments1 e éléments2.
' nova tabela para receber o novo elemento
éléments2 = New Double(i) {}
' cópia da tabela antiga para a nova tabela
If i <> 0 Then
Array.Copy(éléments1, éléments2, i)
End If
' A nova tabela passa a ser a tabela antiga
éléments1 = éléments2
' já não é necessário o novo quadro
éléments2 = Nothing
' inserção de um novo elemento
éléments1(i) = élément
' mais um elemento na tabela
i += 1
A matriz éléments1 contém os valores atualmente introduzidos. Quando o utilizador adiciona um novo valor, cria-se uma matriz éléments2 com mais um elemento do que a éléments1, copia-se o conteúdo de éléments1 para éléments2 (Array.Copy), faz-se com que éléments1 «aponte» para éléments2 e, por fim, adiciona-se o novo elemento a éléments1. Trata-se de um processo complexo que pode ser simplificado se, em vez de utilizar uma matriz de tamanho fixo (Array), se utilizar uma matriz de tamanho variável (ArrayList).
A matriz é ordenada com o método Array.Sort. Este método pode ser chamado com diferentes parâmetros que especificam as regras de ordenação. Sem parâmetros, é efetuada por predefinição uma ordenação crescente. Por fim, o método Array.BinarySearch permite procurar um elemento numa matriz ordenada.
4.5. A classe ArrayList
A classe ArrayList permite implementar tabelas de tamanho variável durante a execução do programa, o que não é possível com a classe Array anterior. Aqui estão algumas das propriedades e métodos mais comuns:
cria uma lista vazia | |
número de elementos da coleção | |
adiciona o objeto «value» ao final da coleção | |
apaga a lista | |
índice do objeto «value» na lista ou -1 se não existir | |
O mesmo, mas a partir do elemento n.º startIndex | |
O mesmo, mas devolve o índice da última ocorrência de «value» na lista | |
O mesmo, mas procurando a partir do elemento n.º startIndex | |
remove o objeto obj, caso exista na lista | |
remove o elemento index da lista | |
retorna a posição do objeto «value» na lista ou -1 se este não se encontrar na lista. A lista deve estar ordenada | |
ordena a lista. Esta deve conter objetos com uma relação de ordem predefinida (cadeias de caracteres, números) | |
ordena a lista de acordo com a relação de ordem estabelecida pela função «comparar» |
Retomemos o exemplo tratado com objetos do tipo Array e processemo-lo com objetos do tipo ArrayList:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Collections
Module test
Sub Main()
' leitura dos elementos de uma tabela introduzidos pelo teclado
Dim terminé As [Boolean] = False
Dim i As Integer = 0
Dim éléments As New ArrayList
Dim élément As Double = 0
Dim réponse As String = Nothing
Dim erreur As [Boolean] = False
While Not terminé
' pergunta
Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
' leitura da resposta
réponse = Console.ReadLine().Trim()
' fim da introdução se a cadeia estiver vazia
If réponse.Equals("") Then
Exit While
End If
' verificação da entrada
Try
élément = Double.Parse(réponse)
erreur = False
Catch
Console.Error.WriteLine("Saisie incorrecte, recommencez")
erreur = True
End Try
' se não houver erro
If Not erreur Then
' mais um elemento na tabela
éléments.Add(élément)
End If
End While
' exibição da tabela não ordenada
System.Console.Out.WriteLine("Tableau non trié")
For i = 0 To éléments.Count - 1
Console.Out.WriteLine(("éléments[" & i & "]=" & éléments(i).ToString))
Next i ' tri du tableau
éléments.Sort()
' exibição da tabela ordenada
System.Console.Out.WriteLine("Tableau trié")
For i = 0 To éléments.Count - 1
Console.Out.WriteLine(("éléments[" & i & "]=" & éléments(i).ToString))
Next i
' Pesquisa
While Not terminé
' pergunta
Console.Out.Write("Elément cherché (rien pour arrêter) : ")
' leitura e verificação da resposta
réponse = Console.ReadLine().Trim()
' terminado?
If réponse.Equals("") Then
Exit While
End If
' verificação
Try
élément = [Double].Parse(réponse)
erreur = False
Catch
Console.Error.WriteLine("Saisie incorrecte, recommencez")
erreur = True
End Try
' se não houver erros
If Not erreur Then
' procura-se o elemento na tabela ordenada
i = éléments.BinarySearch(élément)
' Exibição da resposta
If i >= 0 Then
Console.Out.WriteLine(("Trouvé en position " & i))
Else
Console.Out.WriteLine("Pas dans le tableau")
End If
End If
End While
End Sub
End Module
Os resultados da execução são os seguintes:
Elément (réel) 0 du tableau (rien pour terminer) : 10,4
Elément (réel) 0 du tableau (rien pour terminer) : 5,2
Elément (réel) 0 du tableau (rien pour terminer) : a
Saisie incorrecte, recommencez
Elément (réel) 0 du tableau (rien pour terminer) : 3,7
Elément (réel) 0 du tableau (rien pour terminer) : 15
Elément (réel) 0 du tableau (rien pour terminer) :
Tableau non trié
éléments[0]=10,4
éléments[1]=5,2
éléments[2]=3,7
éléments[3]=15
Tableau trié
éléments[0]=3,7
éléments[1]=5,2
éléments[2]=10,4
éléments[3]=15
Elément cherché (rien pour arrêter) : a
Saisie incorrecte, recommencez
Elément cherché (rien pour arrêter) : 15
Trouvé en position 3
Elément cherché (rien pour arrêter) : 1
Pas dans le tableau
Elément cherché (rien pour arrêter) :
4.6. A classe Hashtable
A classe Hashtable permite implementar um dicionário. Pode-se considerar um dicionário como uma tabela com duas colunas:
![]() |
As chaves são únicas, c.a.d, pelo que não podem existir duas chaves idênticas. Os principais métodos e propriedades da classe Hashtable são os seguintes:
cria um dicionário vazio | |
adiciona uma linha (chave, valor) ao dicionário, em que chave e valor são referências a objetos. | |
elimina do dicionário a linha com a chave=key | |
esvazia o dicionário | |
retorna «true» se a chave «key» pertencer ao dicionário. | |
retorna verdadeiro (true) se o valor value pertencer ao dicionário. | |
propriedade: número de elementos do dicionário (chave, valor) | |
propriedade: coleção das chaves do dicionário | |
propriedade: coleção de valores do dicionário | |
propriedade indexada: permite conhecer ou definir o valor associado a uma chave |
Consideremos o seguinte programa de exemplo:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Collections
Module test
Sub Main()
Dim liste() As [String] = {"jean:20", "paul:18", "mélanie:10", "violette:15"}
Dim i As Integer
Dim champs As [String]() = Nothing
Dim séparateurs() As Char = {":"c}
' preenchimento do dicionário
Dim dico As New Hashtable
For i = 0 To liste.Length - 1
champs = liste(i).Split(séparateurs)
dico.Add(champs(0), champs(1))
Next i
' Número de elementos no dicionário
Console.Out.WriteLine(("Le dictionnaire a " & dico.Count & " éléments"))
' lista de chaves
Console.Out.WriteLine("[Liste des clés]")
Dim clés As IEnumerator = dico.Keys.GetEnumerator()
While clés.MoveNext()
Console.Out.WriteLine(clés.Current)
End While
' lista de valores
Console.Out.WriteLine("[Liste des valeurs]")
Dim valeurs As IEnumerator = dico.Values.GetEnumerator()
While valeurs.MoveNext()
Console.Out.WriteLine(valeurs.Current)
End While
' lista de chaves e valores
Console.Out.WriteLine("[Liste des clés & valeurs]")
clés.Reset()
While clés.MoveNext()
Console.Out.WriteLine(("clé=" & clés.Current.ToString & " valeur=" & dico(clés.Current).ToString))
End While
' elimina-se a chave «paul»
Console.Out.WriteLine("[Suppression d'une clé]")
dico.Remove("paul")
' lista de chaves e valores
Console.Out.WriteLine("[Liste des clés & valeurs]")
clés = dico.Keys.GetEnumerator()
While clés.MoveNext()
Console.Out.WriteLine(("clé=" & clés.Current.ToString & " valeur=" & dico(clés.Current).ToString))
End While
' pesquisa no dicionário
Dim nomCherché As [String] = Nothing
Console.Out.Write("Nom recherché (rien pour arrêter) : ")
nomCherché = Console.ReadLine().Trim()
Dim value As [Object] = Nothing
While Not nomCherché.Equals("")
If dico.ContainsKey(nomCherché) Then
value = dico(nomCherché)
Console.Out.WriteLine((nomCherché + "," + CType(value, [String])))
Else
Console.Out.WriteLine(("Nom " + nomCherché + " inconnu"))
End If
' próxima pesquisa
Console.Out.Write("Nom recherché (rien pour arrêter) : ")
nomCherché = Console.ReadLine().Trim()
End While
End Sub
End Module
Os resultados da execução são os seguintes:
Le dictionnaire a 4 éléments
[Liste des clés]
mélanie
paul
violette
jean
[Liste des valeurs]
10
18
15
20
[Liste des clés & valeurs]
clé=mélanie valeur=10
clé=paul valeur=18
clé=violette valeur=15
clé=jean valeur=20
[Suppression d'une clé]
[Liste des clés & valeurs]
clé=mélanie valeur=10
clé=violette valeur=15
clé=jean valeur=20
Nom recherché (rien pour arrêter) : paul
Nom paul inconnu
Nom recherché (rien pour arrêter) : mélanie
mélanie,10
Nom recherché (rien pour arrêter) :
O programa também utiliza um objeto IEnumerator para percorrer as coleções de chaves e valores do dicionário do tipo ICollection (ver acima as propriedades Keys e Values). Uma coleção é um conjunto de objetos que pode ser percorrido. A interface ICollection é definida da seguinte forma:

A propriedade Count permite-nos saber o número de elementos da coleção. A interface ICollection deriva da interface IEnumerable:

Esta interface possui apenas um método, GetEnumerator, que nos permite obter um objeto do tipo IEnumerator:

O método GetEnumerator() de uma coleção ICollection permite-nos percorrer a coleção com os seguintes métodos:
posiciona no elemento seguinte da coleção. Retorna verdadeiro (true) se esse elemento existir, falso (false) caso contrário. O primeiro MoveNext posiciona no primeiro elemento. O elemento «atual» da coleção fica então disponível na propriedade Current do enumerador | |
propriedade: elemento atual da coleção | |
reposiciona o enumerador no início da coleção, c.a.d, antes do primeiro elemento. |
A estrutura de iteração sobre os elementos de uma coleção (ICollection) em C é, portanto, a seguinte:
' definir a coleção
dim C as ICollection C=...
' obter um enumerador desta coleção
dim itérateur as IEnumerator=C.GetEnumerator();
' percorrer a coleção com este enumerador
while(itérateur.MoveNext())
' temos um elemento atual
' utilizar itérateur.Current
end while
4.7. A classe StreamReader
A classe StreamReader permite ler o conteúdo de um ficheiro. Aqui estão algumas das suas propriedades e métodos:
abre um fluxo a partir do ficheiro path. É lançada uma exceção se este não existir | |
fecha o fluxo | |
lê uma linha do fluxo aberto | |
lê o resto do fluxo a partir da posição atual |
Eis um exemplo:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Collections
Imports System.IO
Module test
Sub Main()
Dim ligne As String = Nothing
Dim fluxInfos As StreamReader = Nothing
' leitura do conteúdo do ficheiro
Try
fluxInfos = New StreamReader("infos.txt")
ligne = fluxInfos.ReadLine()
While Not (ligne Is Nothing)
System.Console.Out.WriteLine(ligne)
ligne = fluxInfos.ReadLine()
End While
Catch e As Exception
System.Console.Error.WriteLine("L'erreur suivante s'est produite : " & e.ToString)
Finally
Try
fluxInfos.Close()
Catch
End Try
End Try
End Sub
End Module
e os seus resultados de execução:
dos>more infos.txt
12620:0:0
13190:0,05:631
15640:0,1:1290,5
24740:0,15:2072,5
31810:0,2:3309,5
39970:0,25:4900
48360:0,3:6898,5
55790:0,35:9316,5
92970:0,4:12106
127860:0,45:16754,5
151250:0,5:23147,5
172040:0,55:30710
195000:0,6:39312
0:0,65:49062
dos>file1
12620:0:0
13190:0,05:631
15640:0,1:1290,5
24740:0,15:2072,5
31810:0,2:3309,5
39970:0,25:4900
48360:0,3:6898,5
55790:0,35:9316,5
92970:0,4:12106
127860:0,45:16754,5
151250:0,5:23147,5
172040:0,55:30710
195000:0,6:39312
0:0,65:49062
4.8. A classe StreamWriter
A classe StreamWriter permite escrever num ficheiro. Aqui estão algumas das suas propriedades e métodos:
abre um fluxo de escrita a partir do ficheiro path. É lançada uma exceção se este não puder ser criado | |
se for igual a verdadeiro, a escrita no fluxo não passa por um buffer; caso contrário, a escrita no fluxo não é imediata: primeiro é escrita num buffer e, depois, no fluxo quando o buffer estiver cheio. Por predefinição, é utilizado o modo com buffer. É adequado para fluxos de ficheiros, mas geralmente não para fluxos de rede. | |
para definir ou saber o caractere de fim de linha a utilizar pelo método WriteLine | |
fecha o fluxo | |
escreve uma linha no fluxo de escrita | |
escreve o buffer no fluxo |
Consideremos o seguinte exemplo:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Collections
Imports System.IO
Module test
Sub Main()
Dim ligne As String = Nothing ' une ligne de texte
Dim fluxInfos As StreamWriter = Nothing ' le fichier texte
Try
' criação do ficheiro de texto
fluxInfos = New StreamWriter("infos.txt")
' leitura da linha digitada no teclado
Console.Out.Write("ligne (rien pour arrêter) : ")
ligne = Console.In.ReadLine().Trim()
' repetir enquanto a linha introduzida não estiver vazia
While ligne <> ""
' gravação da linha no ficheiro de texto
fluxInfos.WriteLine(ligne)
' leitura de uma nova linha introduzida pelo teclado
Console.Out.Write("ligne (rien pour arrêter) : ")
ligne = Console.In.ReadLine().Trim()
End While
Catch e As Exception
System.Console.Error.WriteLine("L'erreur suivante s'est produite : " & e.ToString)
Finally
' fecho do ficheiro
Try
fluxInfos.Close()
Catch
End Try
End Try
End Sub
End Module
e os resultados da execução:
dos>file2
ligne (rien pour arrêter) : ligne1
ligne (rien pour arrêter) : ligne2
ligne (rien pour arrêter) : ligne3
ligne (rien pour arrêter) :
dos>more infos.txt
ligne1
ligne2
ligne3
4.9. A classe Regex
A classe Regex permite a utilização de expressões regulares. Estas permitem verificar o formato de uma cadeia de caracteres. Assim, é possível verificar se uma cadeia que representa uma data está, de facto, no formato dd/mm/aa. Para tal, utiliza-se um padrão e compara-se a cadeia com esse padrão. Assim, neste exemplo, j, m e a devem ser algarismos. O modelo de um formato de data válido é, então, «\d\d/\d\d/\d\d», em que o símbolo \d representa um algarismo. Os símbolos que podem ser utilizados num modelo são os seguintes (documentação da Microsoft):
Descrição | |
Marca o caractere seguinte como caractere especial ou literal. Por exemplo, «n» corresponde ao caractere «n». «\n» corresponde a um caractere de nova linha. A sequência «\\» corresponde a «\», enquanto que «\»(» corresponde a «(». | |
Corresponde ao início da entrada. | |
Corresponde ao fim da introdução. | |
Corresponde ao carácter anterior zero ou mais vezes. Assim, «zo*» corresponde a «z» ou a «zoo». | |
Corresponde ao carácter anterior uma ou mais vezes. Assim, «zo+» corresponde a «zoo», mas não a «z». | |
Corresponde ao carácter anterior zero ou uma vez. Por exemplo, «a?ve?» corresponde a «ve» em «lever». | |
Corresponde a qualquer carácter único, exceto o carácter de nova linha. | |
| Procura o modèle e guarda a correspondência. A subcadeia correspondente pode ser extraída da coleção Matches obtida, utilizando o Item [0]...[n]. Para encontrar correspondências com caracteres entre parênteses ( ), utilize "\(" ou "\)". |
| Corresponde a x ou a y. Por exemplo, «z|foot» corresponde a «z» ou a «foot». «(z|f)oo» corresponde a «zoo» ou a «foo». |
| n é um número inteiro não negativo. Corresponde exatamente a n vezes o carácter. Por exemplo, «o{2}» não corresponde a «o» em «Bob», mas aos dois primeiros «o» em «fooooot». |
| n é um número inteiro não negativo. Corresponde a, pelo menos, n vezes o carácter. Por exemplo, «o{2,}» não corresponde ao «o» em «Bob», mas a todos os «o» em «fooooot». «o{1,}» equivale a «o+» e «o{0,}» equivale a «o*». |
| m e n são números inteiros não negativos. Corresponde a, no mínimo, n e, no máximo, m vezes o carácter. Por exemplo, «o{1,3}» corresponde aos três primeiros «o» em «foooooot» e «o{0,1}» equivale a «o?». |
| Conjunto de caracteres. Corresponde a um dos caracteres indicados. Por exemplo, «[abc]» corresponde a «a» em «plat». |
| Conjunto de caracteres negativo. Corresponde a qualquer caractere não indicado. Por exemplo, «[^abc]» corresponde a «p» em «plat». |
| Intervalo de caracteres. Corresponde a qualquer caractere da série especificada. Por exemplo, «[a-z]» corresponde a qualquer letra minúscula entre «a» e «z». |
| Intervalo de caracteres negativo. Corresponde a qualquer caractere que não se encontre na série especificada. Por exemplo, «[^m-z]» corresponde a qualquer caractere que não se encontre entre «m» e «z». |
Corresponde a um limite que representa uma palavra, ou seja, à posição entre uma palavra e um espaço. Por exemplo, «er\b» corresponde a «er» em «lever», mas não a «er» em «verbe». | |
Corresponde a um limite que não representa uma palavra. «en*t\B» corresponde a «ent» em «bien entendu». | |
Corresponde a um carácter que representa um algarismo. É equivalente a [0-9]. | |
Corresponde a um carácter que não representa um algarismo. É equivalente a [^0-9]. | |
Corresponde a um carácter de salto de página. | |
Corresponde a um carácter de nova linha. | |
Corresponde a um carácter de retorno de carro. | |
Corresponde a qualquer espaço em branco, incluindo espaço, tabulação, salto de página, etc. É equivalente a «[ \f\n\r\t\v]». | |
Corresponde a qualquer caractere de espaço não em branco. É equivalente a «[^ \f\n\r\t\v]». | |
Corresponde a um carácter de tabulação. | |
Corresponde a um carácter de tabulação vertical. | |
Corresponde a qualquer carácter que represente uma palavra e inclua um sublinhado. É equivalente a «[A-Za-z0-9_]». | |
Corresponde a qualquer carácter que não represente uma palavra. É equivalente a «[^A-Za-z0-9_]». | |
| Corresponde a num, em que num é um número inteiro positivo. Refere-se às correspondências memorizadas. Por exemplo, «(.)\1» corresponde a dois caracteres idênticos consecutivos. |
| Corresponde a n, em que n é um valor de escape octal. Os valores de escape octais devem ter 1, 2 ou 3 dígitos. Por exemplo, «\11» e «\011» correspondem ambos a um carácter de tabulação. "\0011" equivale a "\001" e "1". Os valores de escape octais não devem exceder 256. Se tal acontecer, apenas os dois primeiros dígitos serão considerados na expressão. Permite utilizar os códigos ASCII em expressões regulares. |
| Corresponde a n, em que n é um valor de escape hexadecimal. Os valores de escape hexadecimais têm de incluir obrigatoriamente dois dígitos. Por exemplo, «\x41» corresponde a «A». «\x041» equivale a «\x04» e «1». Permite utilizar os códigos ASCII em expressões regulares. |
Um elemento num modelo pode estar presente uma ou mais vezes. Vejamos alguns exemplos relacionados com o símbolo \d, que representa um algarismo:
modelo | significado |
um número | |
0 ou 1 dígito | |
0 ou mais dígitos | |
1 ou mais dígitos | |
2 dígitos | |
pelo menos 3 algarismos | |
entre 5 e 7 dígitos |
Imaginemos agora o modelo capaz de descrever o formato esperado para uma cadeia de caracteres:
cadeia de caracteres procurada | modelo |
\d{2}/\d{2}/\d{2} | |
\d{2}:\d{2}:\d{2} | |
\d+ | |
\s* | |
\s*\d+\s* | |
\s*[+|-]?\s*\d+\s* | |
\s*\d+(.\d*)?\s* | |
\s*[+|]?\s*\d+(.\d*)?\s* | |
\bjuste\b | |
É possível especificar onde se procura o padrão na cadeia:
padrão | significado |
o modelo inicia a cadeia | |
o modelo termina a sequência | |
o modelo inicia e termina a sequência | |
o padrão é procurado em toda a cadeia, começando pelo início da mesma. |
cadeia de caracteres procurada | padrão |
!$ | |
\.$ | |
^// | |
^\s*\w+\s*$ | |
^\s*\w+\s*\w+\s*$ | |
\bsecret\b |
Os subconjuntos de um padrão podem ser «recuperados». Assim, não só é possível verificar se uma cadeia corresponde a um padrão específico, como também é possível recuperar nessa cadeia os elementos correspondentes aos subconjuntos do padrão que foram colocados entre parênteses. Assim, se analisarmos uma cadeia de caracteres que contenha uma data dd/mm/aa e, além disso, quisermos extrair os elementos dd, mm e aa dessa data, utilizaremos o padrão (\d\d)/(\d\d)/(\d\d).
4.9.1. Verificar se uma cadeia corresponde a um modelo determinado
Um objeto do tipo Regex é construído da seguinte forma:
O construtor cria um objeto «expressão regular» a partir de um padrão passado como parâmetro (pattern). Uma vez construída a expressão regular modelo, é possível compará-la com cadeias de caracteres utilizando o método IsMatch:
IsMatch retorna «verdadeiro» se a cadeia de caracteres de entrada corresponder ao padrão da expressão regular. Eis um exemplo:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Module regex1
Sub Main()
' uma expressão regular de padrão
Dim modèle1 As String = "^\s*\d+\s*$"
Dim regex1 As New Regex(modèle1)
' comparar um exemplar com o modelo
Dim exemplaire1 As String = " 123 "
If regex1.IsMatch(exemplaire1) Then
affiche(("[" + exemplaire1 + "] correspond au modèle [" + modèle1 + "]"))
Else
affiche(("[" + exemplaire1 + "] ne correspond pas au modèle [" + modèle1 + "]"))
End If
Dim exemplaire2 As String = " 123a "
If regex1.IsMatch(exemplaire2) Then
affiche(("[" + exemplaire2 + "] correspond au modèle [" + modèle1 + "]"))
Else
affiche(("[" + exemplaire2 + "] ne correspond pas au modèle [" + modèle1 + "]"))
End If
End Sub
' exibe
Sub affiche(ByVal msg As String)
Console.Out.WriteLine(msg)
End Sub
End Module
e os resultados da execução:
dos>vbc /r:system.dll regex1.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>regex1
[ 123 ] correspond au modèle [^\s*\d+\s*$]
[ 123a ] ne correspond pas au modèle [^\s*\d+\s*$]
4.9.2. Encontrar todos os elementos de uma cadeia que correspondam a um padrão
O método Matches
retorna uma coleção de elementos da cadeia input que correspondem ao padrão, conforme ilustrado no exemplo seguinte:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Module regex2
Sub Main()
' várias ocorrências do modelo na instância
Dim modèle2 As String = "\d+"
Dim regex2 As New Regex(modèle2) '
Dim exemplaire3 As String = " 123 456 789 "
Dim résultats As MatchCollection = regex2.Matches(exemplaire3)
affiche(("Modèle=[" + modèle2 + "],exemplaire=[" + exemplaire3 + "]"))
affiche(("Il y a " & résultats.Count & " occurrences du modèle dans l'exemplaire "))
Dim i As Integer
For i = 0 To résultats.Count - 1
affiche((résultats(i).Value & " en position " & résultats(i).Index))
Next i
End Sub
'exibe
Sub affiche(ByVal msg As String)
Console.Out.WriteLine(msg)
End Sub
End Module
A classe MatchCollection tem uma propriedade Count que corresponde ao número de elementos da coleção. Se résultats for um objeto MatchCollection, résultats(i) é o elemento i dessa coleção e é do tipo Match. No nosso exemplo, résultats é o conjunto de elementos da cadeia exemplaire3 que correspondem ao modelo modèle2, sendo résultats(i) um desses elementos. A classe Match tem duas propriedades que nos interessam aqui:
- Value: o valor do objeto Match, ou seja, o elemento correspondente ao modelo
- Index: a posição em que o elemento foi encontrado na cadeia explorada
Os resultados da execução do programa anterior:
dos>vbc /r:system.dll regex2.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4p our Microsoft (R) .NET Framework version 1.1.4322.573
dos>regex2
Modèle=[\d+],exemplaire=[ 123 456 789 ]
Il y a 3 occurrences du modèle dans l'exemplaire
123 en position 2
456 en position 7
789 en position 12
4.9.3. Recuperar partes de um modelo
É possível «extrair» subconjuntos de um modelo. Assim, não só se pode verificar se uma cadeia de caracteres corresponde a um modelo específico, como também se pode extrair dessa cadeia os elementos correspondentes aos subconjuntos do modelo que foram colocados entre parênteses. Assim, se analisarmos uma cadeia de caracteres que contenha uma data dd/mm/aa e, além disso, quisermos extrair os elementos dd, mm e aa dessa data, utilizaremos o modelo (\d\d)/(\d\d)/(\d\d). Vejamos o seguinte exemplo:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Module regex2
Sub Main()
' captura de elementos no modelo
Dim modèle3 As String = "(\d\d):(\d\d):(\d\d)"
Dim regex3 As New Regex(modèle3)
Dim exemplaire4 As String = "Il est 18:05:49"
' verificação do modelo
Dim résultat As Match = regex3.Match(exemplaire4)
If résultat.Success Then
' a cópia corresponde ao modelo
affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
' são apresentados os grupos
Dim i As Integer
For i = 0 To résultat.Groups.Count - 1
affiche(("groupes[" & i & "]=[" & résultat.Groups(i).Value & "] en position " & résultat.Groups(i).Index))
Next i
Else
' o registo não corresponde ao modelo
affiche(("L'exemplaire[" + exemplaire4 + " ne correspond pas au modèle [" + modèle3 + "]"))
End If
End Sub
'apresenta
Sub affiche(ByVal msg As String)
Console.Out.WriteLine(msg)
End Sub
End Module
A execução deste programa produz os seguintes resultados:
dos>vbc /r:system.dll regex3.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4
dos>regex3
L'exemplaire [Il est 18:05:49] correspond au modèle [(\d\d):(\d\d):(\d\d)]
groupes[0]=[18:05:49] en position 7
groupes[1]=[18] en position 7
groupes[2]=[05] en position 10
groupes[3]=[49] en position 13
A novidade encontra-se na seguinte parte do código:
' verificação do modelo
Dim résultat As Match = regex3.Match(exemplaire4)
If résultat.Success Then
' o exemplar corresponde ao modelo
affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
' são apresentados os grupos
Dim i As Integer
For i = 0 To résultat.Groups.Count - 1
affiche(("groupes[" & i & "]=[" & résultat.Groups(i).Value & "] en position " & résultat.Groups(i).Index))
Next i
Else
A cadeia exemplaire4 é comparada com o modelo regex3 através do método Match. Este método devolve um objeto Match já apresentado. Utilizamos aqui duas novas propriedades desta classe:
- Success: indica se houve correspondência
- Groups: coleção em que
- Groups[0] corresponde à parte da cadeia que corresponde ao modelo
- Groups[i] (i>=1) corresponde ao grupo de parênteses n.º i
Se o resultado for do tipo Match, então résultats.Groups é do tipo GroupCollection e résultats.Groups[i] é do tipo Group. A classe Group tem duas propriedades que utilizamos aqui:
- Value: o valor do objeto Group, que corresponde ao conteúdo de um parêntese
- Index: a posição em que o elemento foi encontrado na cadeia analisada
4.9.4. Um programa de treino
Encontrar a expressão regular que nos permite verificar se uma cadeia corresponde efetivamente a um determinado padrão é, por vezes, um verdadeiro desafio. O programa seguinte permite praticar. Solicita um padrão e uma cadeia e indica, em seguida, se a cadeia corresponde ou não ao padrão.
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Imports Microsoft.visualbasic
Module regex4
Sub Main()
' uma expressão regular modelo
Dim modèle, chaine As String
Dim regex As Regex = Nothing
Dim résultats As MatchCollection
' solicita-se ao utilizador os modelos e os exemplares a comparar com este
Dim terminé1 As Boolean = False
Do While Not terminé1
Dim erreur As Boolean = True
Do While Not terminé1 And erreur
' solicita-se o modelo
Console.Out.Write("Tapez le modèle à tester ou fin pour arrêter :")
modèle = Console.In.ReadLine()
' Concluído?
If modèle.Trim().ToLower() = "fin" Then
terminé1 = True
Else
' cria-se a expressão regular
Try
regex = New Regex(modèle)
erreur = False
Catch ex As Exception
Console.Error.WriteLine(("Erreur : " + ex.Message))
End Try
End If
Loop
' Concluído?
If terminé1 Then Exit Sub
' solicita-se ao utilizador os exemplares a comparar com o modelo
Dim terminé2 As Boolean = False
Do While Not terminé2
Console.Out.Write(("Tapez la chaîne à comparer au modèle [" + modèle + "] ou fin pour arrêter :"))
chaine = Console.In.ReadLine()
' concluído?
If chaine.Trim().ToLower() = "fin" Then
terminé2 = True
Else
' faz-se a comparação
résultats = regex.Matches(chaine)
' sucesso?
If résultats.Count = 0 Then
Console.Out.WriteLine("Je n'ai pas trouvé de correspondances")
Else
' são apresentados os elementos que correspondem ao modelo
Dim i As Integer
For i = 0 To résultats.Count - 1
Console.Out.WriteLine(("J'ai trouvé la correspondance [" & résultats(i).Value & "] en position " & résultats(i).Index))
' subelementos
If résultats(i).Groups.Count <> 1 Then
Dim j As Integer
For j = 1 To (résultats(i).Groups.Count) - 1
Console.Out.WriteLine((ControlChars.Tab & "sous-élément [" & résultats(i).Groups(j).Value & "] en position " & résultats(i).Groups(j).Index))
Next j
End If
Next i
End If
End If
Loop
Loop
End Sub
'exibe
Sub affiche(ByVal msg As String)
Console.Out.WriteLine(msg)
End Sub
End Module
Eis um exemplo de execução:
Tapez le modèle à tester ou fin pour arrêter :\d+
Tapez la chaîne à comparer au modèle [\d+] ou fin pour arrêter :123 456 789
J'ai trouvé la correspondance [123] en position 0
J'ai trouvé la correspondance [456] en position 4
J'ai trouvé la correspondance [789] en position 8
Tapez la chaîne à comparer au modèle [\d+] ou fin pour arrêter :fin
Tapez le modèle à tester ou fin pour arrêter :(\d\d):(\d\d)
Tapez la chaîne à comparer au modèle [(\d\d):(\d\d)] ou fin pour arrêter :14:15 abcd 17:18 xyzt
J'ai trouvé la correspondance [14:15] en position 0
sous-élément [14] en position 0
sous-élément [15] en position 3
J'ai trouvé la correspondance [17:18] en position 11
sous-élément [17] en position 11
sous-élément [18] en position 14
Tapez la chaîne à comparer au modèle [(\d\d):(\d\d)] ou fin pour arrêter :fin
Tapez le modèle à tester ou fin pour arrêter :^\s*\d+\s*$
Tapez la chaîne à comparer au modèle [^\s*\d+\s*$] ou fin pour arrêter : 1456
J'ai trouvé la correspondance [ 1456] en position 0
Tapez la chaîne à comparer au modèle [^\s*\d+\s*$] ou fin pour arrêter :fin
Tapez le modèle à tester ou fin pour arrêter :^\s*(\d+)\s*$
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :1456
J'ai trouvé la correspondance [1456] en position 0
sous-élément [1456] en position 0
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :abcd 1
456
Je n'ai pas trouvé de correspondances
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :fin
Tapez le modèle à tester ou fin pour arrêter :fin
4.9.5. O método Split
Já nos deparámos com este método na classe String:
A cadeia de caracteres é considerada como uma sequência de campos separados pelos caracteres presentes na tabela [separator]. O resultado é a tabela desses campos.
O separador de campos da cadeia é, neste caso, um dos caracteres da tabela separator. O método Split da classe Regex permite-nos definir o separador com base num padrão:
A cadeia [input] é decomposta em campos, sendo estes separados por um separador correspondente ao modelo do objeto Regex atual. Suponhamos, por exemplo, que tenhamos num ficheiro de texto linhas com o formato campo1, campo2, …, campo n. Os campos são separados por uma vírgula, mas esta pode ser precedida ou seguida de espaços. O método Split da classe string não é, portanto, adequado. O método RegEx oferece a solução. Se linha for a linha lida, os campos poderão ser obtidos através de
, tal como mostra o exemplo seguinte:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Text.RegularExpressions
Module regex5
Sub Main()
' uma linha
Dim ligne As String = "abc , def , ghi"
' um modelo
Dim modèle As New Regex("\s*,\s*")
' decomposição da linha em campos
Dim champs As String() = modèle.Split(ligne)
' visualização
Dim i As Integer
For i = 0 To champs.Length - 1
Console.Out.WriteLine(("champs[" & i & "]=[" & champs(i) & "]"))
Next i
End Sub
End Module
Resultados da execução:
dos>vbc /r:system.dll regex5.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4
dos>regex5
champs[0]=[abc]
champs[1]=[def]
champs[2]=[ghi]
4.10. As classes BinaryReader e BinaryWriter
As classes BinaryReader e BinaryWriter servem para ler e escrever ficheiros binários. Consideremos a seguinte aplicação. Pretendemos escrever um programa que seria chamado da seguinte forma:
// sintaxe pg texto bin
// lê-se um ficheiro de texto (texto) e o seu conteúdo é guardado num
// ficheiro binário
// o ficheiro de texto contém linhas com o formato nome : idade
// que serão armazenadas numa estrutura string, int
O ficheiro de texto tem o seguinte conteúdo:
O programa é o seguinte:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Text.RegularExpressions
Imports System.IO
' BinaryWriter()
Module bw1
' sintaxe pg texto bin
' lê-se um ficheiro de texto (texto) e o seu conteúdo é guardado num
' ficheiro binário
' o ficheiro de texto contém linhas com o formato nome : idade
' que serão armazenadas numa estrutura string, int
Sub Main(ByVal arguments() As String)
' são necessários 2 argumentos
Dim nbArgs As Integer = arguments.Length
If nbArgs <> 2 Then
Console.Error.WriteLine("syntaxe : pg texte binaire")
Environment.Exit(1)
End If
' abertura do ficheiro de texto para leitura
Dim input As StreamReader = Nothing
Try
input = New StreamReader(arguments(0))
Catch ex As Exception
Console.Error.WriteLine("Erreur d'ouverture du fichier " & arguments(0) & "(" & ex.Message & ")")
Environment.Exit(2)
End Try
' abertura do ficheiro binário para escrita
Dim output As BinaryWriter = Nothing
Try
output = New BinaryWriter(New FileStream(arguments(1), FileMode.Create, FileAccess.Write))
Catch ex As Exception
Console.Error.WriteLine("Erreur d'ouverture du fichier " & arguments(1) & "(" & ex.Message & ")")
Environment.Exit(3)
End Try
' leitura do ficheiro de texto - escrita do ficheiro binário
' linha do ficheiro de texto
Dim ligne As String
' separador dos campos da linha
Dim séparateur As New Regex("\s*:\s*")
' o formato da idade
Dim modAge As New Regex("\s*\d+\s*")
Dim numLigne As Integer = 0
Dim traitementFini As Boolean
Dim champs As String()
ligne = input.ReadLine()
While Not (ligne Is Nothing)
traitementFini = False
' linha vazia?
If ligne.Trim() = "" Then
traitementFini = True
End If
' mais uma linha
If Not traitementFini Then
numLigne += 1
' uma linha com nome: idade
champs = séparateur.Split(ligne)
' são necessários 2 campos
If champs.Length <> 2 Then
Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un nombre de champs incorrect"))
' linha seguinte
traitementFini = True
End If
End If
If Not traitementFini Then
' o segundo campo deve ser um número inteiro >=0
If Not modAge.IsMatch(champs(1)) Then
Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un âge incorrect"))
' linha seguinte
traitementFini = True
End If
' gravamos os dados no ficheiro binário
output.Write(champs(0))
output.Write(Integer.Parse(champs(1)))
End If
'linha seguinte
ligne = input.ReadLine()
End While
' fecho dos ficheiros
input.Close()
output.Close()
End Sub
End Module
Vamos analisar as operações relativas à classe BinaryWriter:
- o objeto BinaryWriter é aberto pela operação
output = New BinaryWriter(New FileStream(arguments(1), FileMode.Create, FileAccess.Write))
O argumento do construtor deve ser um fluxo (Stream). Neste caso, trata-se de um fluxo construído a partir de um ficheiro (FileStream), para o qual se fornece:
- (continuação)
- o nome
- a operação a realizar, neste caso FileMode.Create para criar o ficheiro
- o tipo de acesso, neste caso FileAccess.Write para acesso em escrita ao ficheiro
- a operação de escrita
' os dados são gravados no ficheiro binário
output.Write(champs(0))
output.Write(Integer.Parse(champs(1)))
A classe BinaryWriter dispõe de vários métodos Write sobrecarregados para gravar os diferentes tipos de dados simples
- a operação de encerramento do fluxo
Os resultados da execução anterior serão apresentados pelo programa que se segue. Este também aceita dois argumentos:
' sintaxe pg bin texto
' lê-se um ficheiro binário «bin» e o seu conteúdo é guardado num ficheiro de texto («texto»)
' o ficheiro binário tem uma estrutura string, int
' o ficheiro de texto contém linhas com o formato nome : idade
Fazemos, portanto, a operação inversa. Lemos um ficheiro binário para criar um ficheiro de texto. Se o ficheiro de texto produzido for idêntico ao ficheiro original, saberemos que a conversão texto --> binário --> texto decorreu com sucesso. O código é o seguinte:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Text.RegularExpressions
Imports System.IO
Module br1
' sintaxe pg bin texto
' lê-se um ficheiro binário bin e o seu conteúdo é guardado num ficheiro de texto (texto)
' o ficheiro binário tem uma estrutura string, int
' o ficheiro de texto contém linhas com o formato nome : idade
Sub Main(ByVal arguments() As String)
' são necessários 2 argumentos
Dim nbArgs As Integer = arguments.Length
If nbArgs <> 2 Then
Console.Error.WriteLine("syntaxe : pg binaire texte")
Environment.Exit(1)
End If
' abertura do ficheiro binário para leitura
Dim dataIn As BinaryReader = Nothing
Try
dataIn = New BinaryReader(New FileStream(arguments(0), FileMode.Open, FileAccess.Read))
Catch ex As Exception
Console.Error.WriteLine("Erreur d'ouverture du fichier " & arguments(0) & "(" & ex.Message & ")")
Environment.Exit(2)
End Try
' abertura do ficheiro de texto para escrita
Dim dataOut As StreamWriter = Nothing
Try
dataOut = New StreamWriter(arguments(1))
dataOut.AutoFlush = True
Catch ex As Exception
Console.Error.WriteLine("Erreur d'ouverture du fichier " & arguments(1) & "(" & ex.Message & ")")
Environment.Exit(3)
End Try
' leitura do ficheiro binário - escrita do ficheiro de texto
Dim nom As String ' nom d'une personne
Dim age As Integer ' son âge
' ciclo de processamento do ficheiro binário
While True
' leitura do nome
Try
nom = dataIn.ReadString()
Catch
' fim do ficheiro
Exit Sub
End Try
' leitura da idade
Try
age = dataIn.ReadInt32()
Catch
Console.Error.WriteLine("Le fichier " & arguments(0) + " ne semble pas avoir un format correct")
Exit Sub
End Try
' gravação no ficheiro de texto
dataOut.WriteLine(nom & ":" & age)
System.Console.WriteLine(nom & ":" & age)
End While
' fecha tudo
dataIn.Close()
dataOut.Close()
End Sub
End Module
Vamos analisar as operações relacionadas com a classe BinaryReader:
- o objeto BinaryReader é aberto pela operação
dataIn = New BinaryReader(New FileStream(arguments(0), FileMode.Open, FileAccess.Read))
O argumento do construtor deve ser um fluxo (Stream). Neste caso, trata-se de um fluxo construído a partir de um ficheiro (FileStream), para o qual se fornece:
- (continuação)
- o nome
- a operação a realizar, neste caso FileMode.Open para abrir um ficheiro existente
- o tipo de acesso, neste caso FileAccess.Read para um acesso de leitura ao ficheiro
- a operação de leitura
A classe BinaryReader dispõe de vários métodos ReadXX para ler os diferentes tipos de dados simples
- a operação de encerramento do fluxo
Se executarmos os dois programas em sequência, transformando personnes.txt em personnes.bin e, em seguida, personnes.bin em personnes.txt2, obtemos:

