I/O de ficheiros através de Stream Readers/Writers
Introdução
Operações com ficheiros são essenciais virtualmente em qualquer aplicação. Existem várias formas, cada uma com as suas vantagens e desvantagens, para chegar ao mesmo fim, mas aqui o foco cai sobre os stream readers/writers.
O uso dos stream readers/writers na leitura e escrita de ficheiros torna-se vantajoso quando se tenta estabelecer uma relação de complexidade com velocidade de leitura/escrita. Para além disto, existe mais que um método de leitura e/ou escrita, o que favorece potenciais fins específicos.
Nota: Stream readers/writers encontram-se na framework desde a versão 1.1 abrangido pelo namespace System.IO
.
Reader? Writer? Do que preciso?
Na verdade, a sua funcionalidade é literal. Stream readers (leitores) são utilizados para a leitura ao passo que stream writers (escritores) são utilizados para escrita. Se a necessidade for a leitura dos conteúdos de um ficheiro, usa-se StreamReader
para o fazer. Se pelo contrário a necessidade for escrever num ficheiro, quer ele exista ou não, usa-se StreamWriter
para o fazer.
Ler de um ficheiro
Em todas as soluções de leitura, o caminho do ficheiro é hipotético e pode ser substituído por uma variável. Serão utilizadas as MessageBox
es como meio de mostrar o resultado da leitura, a título de exemplo.
Importante: Se o ficheiro não existir, estiver aberto ou numa localização inacessível, é lançada uma excepção.
Ler um caractere
É possível ler o ficheiro caractere a caractere, descartando (na ordem) o caractere anterior:
Dim SR As New IO.StreamReader("O_meu_ficheiro.txt")
While Not SR.EndOfStream
MsgBox(Chr(SR.Read))
End While
SR.Close()
Nota: É necessário utilizar o método CHR() no resultado, pois o valor devolvido corresponde ao código do caractere e não ao caractere em si.
Ler uma linha inteira
É possível ler o ficheiro linha a linha, descartando (na ordem) a linha anterior:
Dim SR As New IO.StreamReader("O_meu_ficheiro.txt")
While Not SR.EndOfStream
MsgBox(SR.ReadLine)
End While
SR.Close()
Espreitar o próximo caractere, sem descartar
É possível ler o próximo caractere na sequência, sem o descartar. O caractere obtido vai ser o resultado do próximo read:
Dim SR As New IO.StreamReader("O_meu_ficheiro.txt")
MsgBox(Chr(SR.Peek()))
SR.Close()
Ler o ficheiro do início ao fim
Por fim, é possível ler todo o conteúdo do ficheiro de uma só vez:
Dim SR As New IO.StreamReader("O_meu_ficheiro.txt")
MsgBox(SR.ReadToEnd)
SR.Close()
Este método dispensa o uso do ciclo while para determinar o final do ficheiro, pois a sua finalidade é ler todo o conteúdo desde a posição em que se encontra na ordem até ao final, independentemente de onde o final esteja.
O que é o Readblock? Faz parte da classe...
ReadBlock
é um outro método de leitura que deriva do método Read
. Para além de existir na classe, este não é mencionado através do intellisense padrão. Este método difere do Read
apenas na possibilidade de estipular um máximo de caracteres a ler para um buffer. Um exemplo da sua utilização, a ler 30 caracteres:
Dim SR As New IO.StreamReader("O_meu_ficheiro.txt")
Dim buffer(30) As Char
While Not SR.EndOfStream
SR.ReadBlock(buffer, 0, 30)
End While
SR.Close()
For Each C As Char In buffer
MsgBox(C)
Next
Por que razão não é possível ler caracteres especiais, como acentos?
Sem dar a indicação do tipo de codificação presente no conteúdo que se está a ler, todos os caracteres que não façam parte do padrão (baseado na lingua inglesa) são devolvidos como um caractere padrão sem significado. Nos métodos de leitura devemos incluír sempre a indicação do tipo de codificação da informação que se vai tentar ler.
O StreamReader
ostenta, para ficheiros, 5 overloads diferentes. Ei-los, discriminando argumentos:
Path
Caminho do ficheiro.Path
,detectEncodingFromByteOrderMarks
Caminho do ficheiro e umBoolean
para detectar ou não a codificação automaticamente (se disponível no formato).Path
,Encoding
Caminho do ficheiro e uma codificação da classeEncoding
emSystem.Text.Encoding
.Path
,Encoding
,detectEncodingFromByteOrderMarks
Combinação para determinar uma codificação caso não seja automaticamente detectada.Path
,Encoding
,detectEncodingFromByteOrderMarks
,buffersize
Combinação anterior e estipulação do tamanho máximo do buffer de leitura.
Exemplo de utilização com codificação padrão (para a maioria dos caracteres comuns):
Dim SR As New IO.StreamReader("O_meu_ficheiro.txt", System.Text.Encoding.Default)
While Not SR.EndOfStream
MsgBox(SR.ReadLine())
End While
SR.Close()
Escrever para um ficheiro
Em todas as soluções de escrita, o caminho do ficheiro é hipotético e pode ser substituído por uma variável. O resultado escrito no ficheiro encontra-se depois da solução. O ciclo For
serve única e exclusivamente para gerar conteúdo. A sua aplicação não é obrigatória, nem necessária.
Escrever uma sequência a partir do final do ficheiro
É possível escrever no ficheiro, sequencias de caracteres, sempre a partir da última posição do ficheiro.
Dim SW As New IO.StreamWriter("O_meu_ficheiro.txt")
For i As Integer = 0 To 10
SW.Write(i)
Next
SW.Close()
012345678910
Escrever uma linha a partir do final do ficheiro
É possível escrever no ficheiro, sequencias de caracteres seguidas do terminador de linha, sempre a partir da última posição do ficheiro.
Dim SW As New IO.StreamWriter("O_meu_ficheiro.txt")
For i As Integer = 0 To 10
SW.WriteLine(i)
Next
SW.Close()
0
1
2
3
4
5
6
7
8
9
10
Continuar a escrever um ficheiro existente
Para além dos já mencionados codificação e buffersize, o argumento append consta em alguns overloads do inicializador do StreamWriter
. Append
é uma variável do tipo boolean
e visa determinar se a escrita deverá começar no início do ficheiro (overwrite) ou se deverá começar no final do ficheiro. Exemplo de um append (a primeira caixa representa o conteúdo original):
Conteúdo original
Dim SW As New IO.StreamWriter(sfd.FileName, True)
For i As Integer = 0 To 10
SW.WriteLine(i)
Next
SW.Close()
Conteúdo original
0
1
2
3
4
5
6
7
8
9
10
Importante: O StreamWriter
escreve por cima de ficheiros existentes sem lançar excepções.
Aviso: Em ambas leitura e escrita, se o stream não for fechado através do método Close()
, o ficheiro fica aberto e reservado à aplicação até que esta termine, ou até que o stream seja fechado.