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!

Excel: Criação de Fórmulas Personalizadas

O Microsoft Excel tem inúmeras fórmulas para diversos utilizações, muitas delas que nem sabemos da sua existência nem sabemos para que serve. Tem fórmulas para quase tudo! Mas no entanto existem operações que por serem muito específicas ou simplesmente para simplificar (de modo a não utilizar muitas fórmulas em conjunto) dava jeito serem personalizadas, ou seja, à nossa medida.

A verdade é que não é prático utilizar algo do género:

{=IF(FORMULA(<criteria>)=0;IF(MATCH(<range>;<criteria>); ....

A fórmula além de complicada de construir é também complicada de interpretar e alterar. Nestes casos o ideal é criarmos a nossa própria fórmula permitindo, além de simplificar, executar mais funcionalidades para além das já existentes e disponíveis.

Para demonstrar a criação de uma fórmula personalizada, será mostrado um exemplo de como recolher a primeira e ultima palavra de um nome completo, construindo um nome abreviado.

Nota: Esta funcionalidade poderá também ser construída através de fórmulas, mas o objectivo é mostrar a melhoria que estas fórmulas predefinidas podem trazer às folhas de cálculo.

Para adicionarmos esta função a uma folha de Excel devemos fazer o seguinte:

1 – Menu Tools – Macros – Visual Basic Editor ou ALT+F11

2 – Adicionar um novo módulo clicando com o botão direito ou através do menu Insert (Figura 1)

 
                                  (Figura 1)

3 – Colocar a seguinte código no módulo criado:

    ' ---------------------------------------------------------------------------
    ' Separa uma frase e retorna o primeiro e último nome
    ' ---------------------------------------------------------------------------

    Public Function FirstLast(ByVal str As String) As String
        Dim result() As String
        Dim total As Integer

        ' Separa para um array o valor da célula de acordo com o   
        ' separador " "
ou seja espaço

        ' Por exemplo na frase "isto é um teste" o resultado ficará desta forma:
       
        ' result(0) = isto
        ' result(1) = é
        ' result(2) = um
        ' result(3) = teste
       
        result = Split(str, " ")

        ' Verifica qual o tamanho do array (o array começa em zero)
        total = UBound(result)

        ' Caso seja zero
        If total = 0 Then

            If str = "" Then

                ' Caso esteja em branco não retorna nada
                FirstLast = ""

            Else

                ' Caso exista texto retorna esse texto
                FirstLast = StrConv(str, vbProperCase)

            End If

        Else

            ' Retorna o primeiro nome e o último, com um espaço no 
            ‘  meio utiliza ainda a função StrConv()
que converte
            ‘  o
texto (neste caso) para um formato the Proper Case
            FirstLast = StrConv(result(0), vbProperCase) & Space(1) & _
                        StrConv(result(total), vbProperCase)

        End If

    End Function

         

4 – Fechar o Editor de VBA e na folha de cálculo utilizar a função criada

O exemplo deste pequeno artigo é mostrar que as fórmulas personalizadas, utilizando VBA, permitem melhorar e potenciar as folhas de cálculo. É mostrado um exemplo simples que pretende explicar o funcionamento geral mas também mostrar algumas instruções de código (como o caso de arrays, StrConv, Split, etc).

         

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