Visual Basic em Português

Página pessoal de Jorge Paulino sobre o Visual Basic (VB.NET, ASP.NET, VB6, VBA) e algumas noticias de tecnologia

VB.NET: Utilização de Ficheiros de Texto

A utilização e manipulação de ficheiros de texto (*. txt ou outra extensão) é muito comum embora existam bastantes alternativas disponíveis para guardar informação. No entanto, muitas vezes não é uma questão de alternativa (usar ou não usar) mas sim uma necessidade.

O .NET Framework 2.0 introduziu novos métodos que possibilitam um fácil e rápido acesso. Os métodos mais utilizados e mais eficazes para ler e escrever em ficheiros de texto são os namespaces IO (através da classe File, principalmente ReadAllLines, WriteAllText e AppendAllText e o StreamReader, StreamWriter) e o My (através da classe My.Computer.FileSystem, principalmente ReadAllText e WriteAllText).

Obviamente que existem diferenças entre eles, mas as principais diferenças são que o StreamReader e StreamWriter lê/escreve linha a linha e os outros métodos lêem/escrevem tudo de uma só vez, ou seja, utilizam mais recursos da aplicação. Por exemplo o StreamReader lê linha a linha enquanto o método ReadAllLines lê toda a informação para uma variável (array).

É claro que isto apenas se consegue notar em grande número de informação, mas para verem as principais diferenças e desempenhos vejam a seguinte tabela com os tempos de acesso em milisegundos.

Tempo Médio de Leitura

Método/Nº Linhas

10.000

100.000

1.000.000

IO.File.ReadAllLines

4,0

71,2

957,1

IO.StreamReader

2,6

33,9

313,1

My.Computer.FileSystem.ReadAllText

6,7

60,5

991,2

Tempo Médio de Leitura

Método/Nº Linhas

10.000

100.000

1.000.000

IO.File.WriteAllText

15,1

123,8

1.426,4

IO.StreamWriter

13,8

115,5

1.922,8

My.Computer.FileSystem.WriteAllText

15,3

116,8

1.389,1

Nota: Tempo em milisegundos com a média de 10 leitura e texto por linha de 13 caracteres

Para mostrar um pouco a utilização dos diferentes métodos serão mostrados dois exemplos da leitura e escrita. Como o IO.File e o My.Computer.FileSystem são bastante semelhantes, onde a principal diferença é que a classe IO.File tem um método que lê todas as linhas sem necessitar de utilizar uma função de Split() para as colocar num array, irá ser mostrado apenas este. O My.Computer.FileSystem tem ainda um parametro adicionar que permite adicionar, ou não, texto a um arquivo já existente (append).

Exemplo de leitura de um ficheiro através do classe IO.File (ReadAllLines)

        Dim total As Integer = 0
        Dim fileName As String = "c:\teste.txt"

        ' Guarda num Array linha a linha
        Dim lines() As String = IO.File.ReadAllLines(fileName)

        ' Ciclo que irá mostrar linha a linha
        For Each line As String In lines

            Debug.WriteLine(line.ToString)
            total += 1

        Next

        ' Mostra o total de linha lidas
        Debug.WriteLine("Total de linhas:" & total.ToString)

Exemplo de escrita de um ficheiro através do classe IO.File (WriteAllText)

        Dim total As Integer = 0
        Dim fileName As String = "c:\teste.txt"

        ' Cria um novo StringBuilder
        Dim sb As New System.Text.StringBuilder                                   

        ' Ciclo que irá inserir construir o ficheiro a gravar
        For x As Integer = 0 To 9999

            ' Cria uma linha com o formato "Linha nº 0001"
            sb.AppendLine("Linha nº " & x.ToString.PadLeft(4, "0"))
            total += 1
        Next

        ' Grava o ficheiro no disco
        IO.File.WriteAllText(fileName, sb.ToString)

        ' Mostra o resultado
   Debug.WriteLine(String.Format("Ficheiro {0} com {1} registos", fileName, total))

Exemplo de leitura de um ficheiro através do classe IO (StreamReader)

        Dim total As Integer = 0
        Dim fileName As String = "c:\teste.txt"

        ' Ciclo que irá mostrar linha a linha
        Using reader As New IO.StreamReader(fileName)

            ' Ciclo até ao fim do ficheiro
            While Not reader.EndOfStream()

                ' Mostra o resultado linha a linha
                Dim input As String = reader.ReadLine()
                Debug.WriteLine(input)
                total += 1                                   

            End While                                   

        End Using

        ' Mostra o total de linha lidas
        Debug.WriteLine("Total de linhas:" & total.ToString)

Exemplo de escrita de um ficheiro através do classe IO (StreamWriter)

        Dim total As Integer = 0
        Dim fileName As String = "c:\teste.txt"                                   

        ' Cria um nova instância de um StreamWriter
        Using writer As New IO.StreamWriter(fileName)

            ' Inicia o ciclo que irá gravar no ficheiro
            For x As Integer = 0 To 9999

                writer.WriteLine("Linha nº " & x.ToString.PadLeft(4, "0"))
                total += 1

            Next

        End Using

        ' Mostra o resultado
   Debug.WriteLine(String.Format("Ficheiro {0} com {1} registos", fileName, total))

Estes são pequenos exemplos da estrutura tipo, embora existam ainda em cada classe, uma serie de métodos que podem ser utilizados. Pelos exemplos mostrados e pelo desempenho de cada um, deverá ser utilizado aquele que mais se ajustar a cada situação. Apenas em ficheiros grandes deverá haver um mais cuidado na escolha do método a utilizar.

Todos utilizam por defeito uma codificação de UTF-8 mas por vezes é necessário ajustar para certos ficheiros. A opção System.Text.Encoding.Default é muitas vezes a melhor solução para problemas de codificação.

                                

PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!


VB.NET: Dicas de Programação #6

DateTimePicker – Sem Selecção (nulo)

   

O DateTimePicker é um excelente controlo para seleccionar e mostrar datas ou horas. Não necessita de validação, é fácil de seleccionar ou incrementar, permite uma introdução directa e é visualmente bastante agradável. Mas, e como não há regra sem excepção, tem um grande defeito: não tem uma possibilidade directa simples de indicar que não existe escolha, ou seja, colocar uma selecção a nulo.

   

Quando estamos a inserir ou a mostrar dados, o controlo DateTimePicker indica sempre uma data/hora. Isto obriga a uma adaptação por parte do programador, criando um conjunto de soluções alternativas, para indicar que não existe nenhuma selecção. Há quem coloque uma data (tipo 01-01-1900), há quem coloque uma checkbox para habilitar/desabilitar o controlo e há quem simplesmente não o utilize.

 

   

A melhor solução, e é obviamente a minha opinião, é mostrar sem nada (em branco), indicando que não tem selecção. Para fazer isto é necessário o seguinte:

   

DATA

   

Para mostrar a data em branco é necessário definir o controlo DateTimePicker com o formato Custom (personalizado) e indicar um espaço em branco (“ “)

   

    Me.DateTimePicker1.Format = DateTimePickerFormat.Custom

    Me.DateTimePicker1.CustomFormat = " "

   

Depois, e quando o utilizador seleccionar uma data, repomos o formato normal

   

    Private Const EmptySpace As String = " "

   

    ' Detecta que foi alterado um valor(data) no DateTimePicker

    Private Sub DateTimePicker1_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) _

                                        Handles DateTimePicker1.ValueChanged

   

        ' Verifica se o texto é um espaço em branco

        If DateTimePicker1.Text = EmptySpace Then

   

            ' Define o formato como Shot (formato DD-MM-YYYY) e dá um

            ' enter para fechar (CloseUp) da janela que está aberta

            Me.DateTimePicker1.Format = DateTimePickerFormat.Short

            SendKeys.Send("{ENTER}")

   

        End If

   

    End Sub

   

   

HORA

   

Como no caso anterior é necessário definir o controlo DateTimePicker com o formato Custom (personalizado) e indicar um espaço em branco (“ “). O problema é que neste caso o utilizador inicia a alteração da hora/ através dos botões UpDown uma vez que não consegue introduzir manualmente (não permite o focus uma vez que não tem valores). Para detectarmos que o utilizador clicou com o rato num botão de incremento/decremento é necessário fazer o override ao WndProc, uma vez que os eventos MouseDown ou MouseUp não detectam os botões.

   

O melhor é criar um controlo personalizado em que se define este processo. No exemplo o controlo tem o nome de myDateTimePicker.

   

   

  Me.MyDateTimePicker1.ShowUpDown = True

  Me.MyDateTimePicker1.Format = DateTimePickerFormat.Custom

  Me.MyDateTimePicker1.CustomFormat = " ""

   

O código para o controlo personalizado, fazendo o override ao WndProc é o seguinte:

   

           

Public Class myDateTimePicker

    Inherits DateTimePicker

   

    Const EmptySpace As String = " "

   

    ' Constante que verifica se foi utilizado o botão esquerdo do rato

    Private Const WM_LBUTTONDOWN = &H201

   

    ' Overrides ao WndProc

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

   

        ' Caso seja o botão esquerdo e o texto esteja com um espaço em branco

        If m.WParam = WM_LBUTTONDOWN Then

            If Me.Text = EmptySpace Then

   

                Me.Format = DateTimePickerFormat.Time

   

            End If

        End If

   

        MyBase.WndProc(m)

   

    End Sub

   

End Class

   

   

Para terminar, pode-se ainda apagar a formatação quando o utilizador pressionar a tecla DEL, nos eventos KeyUp, KeyDown ou KeyPress.

   

   

    Private Sub MyDateTimePicker1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) _

                     Handles MyDateTimePicker1.KeyDown

   

        ' Caso a tecla seja a DELETE

        If e.KeyCode = Keys.Delete Then

            Me.MyDateTimePicker1.Format = DateTimePickerFormat.Custom

            Me. MyDateTimePicker1.CustomFormat = " "

        End If

   

    End Sub

   

   

Este é um exemplo de como melhorar a utilização deste controlo tornando-o quase “perfeito”.

   

 

StopWatch Medindo o Tempo de Execução

   

Existem formas diferentes de construir código de modo a executar algo. Umas mais rápidas, umas mais simples ou mesmo mais versáteis. As operações mais demoradas estão normalmente relacionadas com a gestão de dados (bases de dados, ficheiros, etc.) mas as pequenas optimizações em conjunto, podem melhorar a performance da aplicação. Nos casos de duvida, em que qual é o método mais rápido para fazer algo, o melhor mesmo é testar.

   

O StopWatch permite medir de uma forma bastante simples o tempo de execução, utilizando muito pouco código. O método para testar o tempo de execução de diferentes métodos é sempre o mesmo, ou seja:

   

  .  ' Cria-se uma nova instância

    Dim stopWatch As New Stopwatch

   

    ' Inicia-se a contagem

    stopWatch.Start()

   

    ' Faz-se um ciclo com várias repetições para verificar o tempo que demorou

    ' a executar. Caso o código já seja demorado, não é necessário ciclo

    For x As Integer = 0 To 10000

        ' código a testar

    Next

   

    ' Para-se a contagem

    stopWatch.Stop()

   

    ' Mostra-se o tempo que demorou a executar em milisegundos

    Debug.WriteLine(stopWatch.ElapsedMilliseconds.ToString)

   

Depois repetem-se algumas vezes, coloca-se o código de comparação a testar e comparam-se os resultados obtidos. Pode ser necessário ajustar o número de repetições no ciclo de maneira a diferenciar melhor os resultados.

   

Podem-se ainda melhorar a visualização, especialmente em tarefas mais demoradas, utilizando o TimeSpan. Depois de parar o Stopwatch, através do método Stop(), pode-se fazer o seguinte:

   

      ' Coloca o tempo total na variável do tipo TimeSpan.

      Dim ts As TimeSpan = stopWatch.Elapsed

   

      ' Mostra a informação dividida em Horas, Minutos, Segundo e Milisegundos.

      Dim totalTime As String = _

String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

      Debug.WriteLine(totalTime)

   

   

O exemplo mostrar como aplicar e executar testes de velocidade de código, com o objectivo de melhorar a performance da aplicação.

 

PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!


VB6: Guardar Configurações - INI vs Registry

A maioria das aplicações tem algumas opções que são importantes guardar de modo a serem utilizadas durante e em próximas execuções. Estas configurações ou settings são bastante utilizadas e importantes, sendo os métodos mais usados no Visual Basic 6 a criação de ficheiros INI’s e a utilização do Registry do Windows.

 

Tamanho e/ou localização de uma janela, data do último acesso, impressora utilizada, nome do último login, são apenas alguns exemplos do que é “normal” e necessário guardar. Pode-se obviamente também guardar esta informação numa base de dados, mas se necessitarmos de guardar o endereço da base de dados ou o nome do servidor? É necessário recorrer a outros métodos.

 

Actualmente, e embora também se utilize também no Visual Basic 6, os ficheiros XML estão a liderar os ficheiros de settings fazendo parte de várias classes do Visual Basic.NET o que simplifica bastante este processo. Existe ainda um processo de criação de settings embebido na aplicação.

 

Existem grandes defensores dos ficheiros INI’s e grandes defensores de guardar a informação no Registry do Windows, no entanto, e é a minha opinião pessoal, é que ambos os métodos são válidos e devem ser utilizados para diferentes fins.

 

Ambos têm vantagens e desvantagens, por exemplo: os ficheiros INI’s são fáceis analisar, não necessitam de acesso de administrador para os modificar/criar, mas também são fáceis de modificar não oferecendo por isso nenhuma segurança. Por outro lado a utilização do Registry do Windows necessita de acesso de administrador (o que em muitos sistemas é impensável), é mais delicada a sua utilização pois podem-se apagar/modificar inadvertidamente outras informações importantes no Registry e é mais difícil de analisar a informação sendo necessário recorrer a um editor. No entanto é bastante mais seguro.

 

Podem ser utilizados os dois sistemas, de acordo com a interpretação de cada programador, por exemplo, guardar informações mais importantes (como passwords) no Registry e informações menos importantes/relevantes em ficheiros INI.

 

Ficheiros INI’s

 

Os ficheiros INI’s não são mais do que ficheiros de texto em que se guardam informações devidamente agrupadas o que permitem uma boa organização e fácil acesso através de API’s. A estrutura de um ficheiro é:

 

 [Secção1]

Chave1=Texto1

Chave2=Texto2

 

[Secção2]

Chave1=Texto1

Chave2=Texto2

 

Este é um exemplo simples de utilização:

 

Option Explicit

 

' Declaração de API's

Private Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" _

     (ByVal lpApplicationName As String, ByVal lpKeyName As Any, _

      ByVal lpString As Any, ByVal lpFileName As String) As Long

 

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" _

     (ByVal lpApplicationName As String, ByVal lpKeyName As Any, _

      ByVal lpDefault As String, ByVal lpReturnedString As String, _

      ByVal nSize As Long, ByVal lpFileName As String) As Long

                       

                       

' Escreve no ficheiro INI através de API ignorando o erro

Public Function INIWrite(sSection As String, sKeyName As String, sNewString As String, sINIFileName As String) As Boolean

 

  Call WritePrivateProfileString(sSection, sKeyName, sNewString, sINIFileName)

  INIWrite = (Err.Number = 0)

 

End Function

 

 

' Lê no ficheiro INI através de API ignorando o erro

Public Function INIRead(sSection As String, sKeyName As String, sINIFileName As String) As String

Dim sRet As String                       

 

  sRet = String(255, Chr(0))

  INIRead = Left(sRet, GetPrivateProfileString(sSection, ByVal sKeyName, "", sRet, Len(sRet), sINIFileName))

 

End Function

 

 

' No evento Form Load

Private Sub Form_Load()

 

    ' Escreve uma informação no ficheiro INI. Caso exista modifica a existente,

    ‘ caso não exista cria uma nova chave e o respectivo texto

    Call INIWrite("GERAL", "utilizador", "jpaulino", App.Path & "\mySettings.ini")

 

End Sub

 

 

' Botão para mostrar o resultado

Private Sub btnRead_Click()

    Dim result As String

   

    ' Lê a chave no ficheiro INI para uma variável e mostra a informação

    result = INIRead("GERAL", "utilizador", App.Path & "\mySettings.ini")

    MsgBox result, vbInformation

   

End Sub

 

 

O resultado no evento Form Load será a criação de um ficheiro ini (mySettings.ini) com a seguinte estrutura:

 

[GERAL]

utilizador=jpaulino

 

 

Windows Registry

 

A utilização do Windows Registry é ainda mais fácil, não sendo necessário a utilização de API’s. A localização onde é guardada a informação é fixa e é a seguinte:

 

HKEY_CURRENT_USER
      \Software
         \VB and VBA Program Settings
            \Applicação
               \ Secção

                  Chave = Texto

 

Este é um exemplo simples de utilização:

 

Option Explicit

 

' Escreve a informação no Registry

Private Sub bntWrite_Click()

 

    SaveSetting "Teste", "GERAL", "Página", "http://vbtuga.blogspot.com/"

   

End Sub

 

 

' Botão para mostrar o resultado

Private Sub btnRead_Click()

 

    Dim result As String

    result = GetSetting("Teste", "GERAL", "Página", "")

   

    MsgBox result, vbInformation

 

End Sub

 

 

Como já referido anteriormente, existem actualmente outros métodos para guardar informação relevante à aplicação, mas estas duas formas são ainda utilizadas. Muitos programadores de Visual Basic 6 que migraram para Visual Basic.Net ainda utilizam estes métodos (embora não aconselhável).

 

Este artigo, embora bastante simples, pretende apenas mostrar algumas alternativas fáceis e eficazes de guardar informações de configuração da aplicação e como as utilizar de uma forma geral.



PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!



Microsoft Office Especialist

Membro da Comunidade
Experts-Exchange


Administ. da Comunidade
Portugal-a-Programar



Twitter

Artigos no CodeProject

Artigos no CodeProject

Subscrever Novidades

Endereço de Email:

Delivered by FeedBurner

Seguidores

Histórico