Ir para o conteúdo

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 MessageBoxes 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 um Boolean para detectar ou não a codificação automaticamente (se disponível no formato).
  • Path, Encoding
    Caminho do ficheiro e uma codificação da classe Encoding em System.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.