VB - Copiando arquivos com barra de progresso


Neste artigo vou mostrar , usando a forma estruturada e clássica de codificação , como copiar arquivos e exibir e acompanhar a tarefa por meio de uma barra de progresso.

O projeto e o código é simples mas pode servir de grande ajuda para quem esta começando agora com a linguagem VB.

Neste projeto eu vou o componente CommonDialog para exibir a janela Procurar Arquivo e vou  usar também uma API que será usada para fazer a mesma coisa. O objetivo é mostrar que você pode substituir o controle CommonDialog por uma API.

Inicie então uma nova versão do VB6 ou do VB5 ( o projeto roda nas duas versões) e no formulário principal inclua os controles conforme o layout abaixo:

Controles usados no projeto:

- 2 caixas de texto : caminhoOrigem.text e caminhoDestino.text

- 4 botões de comando - procuraOrigem e procuraDestino , Copiar e Encerra

- 1 Barra de Progresso - pbCopiaArquivos

- 1 CommonDialog - dialogo

- formulário CopiaArquivo.frm

- projeto : CopiarArquivos.vbp

Inclua no projeto um módulo .bas chamado - CopiaArq.bas e nele digite o código abaixo que irá declarar as API´s usadas para exibir a janela Procurar Arquivo:

Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal pszPath As String) As Long
Declare Function SHGetSpecialFolderLocation Lib "shell32.dll" (ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As ITEMIDLIST) As Long
Declare Function SHBrowseForFolder Lib "shell32.dll" Alias "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) As Long


Type SHITEMID
  cb As Long
  abID As Byte
End Type

Type ITEMIDLIST
   mkid As SHITEMID
End Type

Type BROWSEINFO
  hOwner As Long
  pidlRoot As Long
  pszDisplayName As String
  lpszTitle As String
  ulFlags As Long
  lpfn As Long
  lParam As Long
  iImage As Long
End Type

Public Const NOERROR = 0

Public Const BIF_RETURNONLYFSDIRS = &H1
Public Const BIF_DONTGOBELOWDOMAIN = &H2
Public Const BIF_STATUSTEXT = &H4
Public Const BIF_RETURNFSANCESTORS = &H8
Public Const BIF_BROWSEFORCOMPUTER = &H1000
Public Const BIF_BROWSEFORPRINTER = &H2000

Agora no formulário do projeto no evento Click do primeiro botão Procura para origem insira o seguinte código :

Private Sub procuraOrigem_Click()

Dialog.DialogTitle = "Procura origem..." 'define o titulo
Dialog.ShowOpen 'exibe o dialogo
caminhoOrigem.Text = Dialog.FileName 'define o texto da caixa de origem

End Sub

Este código irá abrir a janela de diálogo Procurar Arquivo

No evento Click do outro botão Procura para destino insira o código a seguir :

Private Sub procuraDestino_Click()
Dim bi As BROWSEINFO 'declara as variaveis
Dim rtn&
Dim pidl&
Dim path As String
Dim pos As Integer

bi.hOwner = Me.hWnd 'centraliza o dialogo na tela
bi.lpszTitle = "Procura destino..." 'define o titulo do texto
bi.ulFlags = BIF_RETURNONLYFSDIRS 'o tipo de pasta para retornar
pidl& = SHBrowseForFolder(bi) 'exibe o dialogo

path = Space(512) 'define o tamanho maximo
T = SHGetPathFromIDList(ByVal pidl&, ByVal path) 'obtem o caminho selecionado

pos% = InStr(path$, Chr$(0)) 'extrai o caminho da string
SpecIn = Left(path$, pos - 1) 'define o caminho extraido

If Right$(SpecIn, 1) = "\" Then 'esteja certo de que a barra "\" esta no fim do caminho
saida = SpecIn 'se nao estiver , nao faça nada
Else 'senao
saida = SpecIn + "\" 'inclui a barra "\" no fim do caminho
End If

caminhoDestino.Text = saida + ExtraiNome(caminhoOrigem.Text) 'monta o nome dos arquivos

End Sub

Este código também abre uma janela para Procurar Arquivos . mas usa a API do Windows. (Note que as janelas são diferentes)

No evento Click do botão - Copiar - inclua o código abaixo que irá chamar a rotina para efetuar a copia dos arquivos selecionados:

Private Sub Copiar_Click()
On Error Resume Next 'ignora quaisquer erros

If caminhoOrigem.Text = "" Then 'tenha certeza de que a origem foi informado
MsgBox "Você deve definir o nome e o caminho do arquivo de origem.", vbCritical 'se não informar exibe mensagem
Exit Sub 'sai da rotina
End If
If caminhoDestino.Text = "" Then 'tenha certeza de que o arquivo de destino foi informado
MsgBox "Você deve definir o nome e caminho do arquivo de destino.", vbCritical 'se nao informar exibe mensagem
Exit Sub 'sai da rotina
End If

'se tudo estiver correto então copia o arquivo
pbCopiaArquivos.Value = CopiarArquivo(caminhoOrigem.Text, caminhoDestino.Text)
End Sub

A função mais importante é a função CopiarArquivo() que possui o seguinte código :

Function CopiarArquivo(Origem As String, Destino As String) As Single

'declara as variaveis
Static Buf As String
Dim BTest As Long
Dim FSize As Long
Dim Chunk As Integer
Dim F1 As Integer
Dim F2 As Integer

Const BUFSIZE = 1024 'define o tamanho do buffer

If Len(Dir(Destino)) Then 'verifica se o arquivo de destino ja existe
Resposta = MsgBox(Destino + Chr(10) + Chr(10) +  _
"Arquivo já existe. Deseja sobrescrever o arquivo existente ?", vbYesNo + vbQuestion) 'exibe ao usuário uma caixa de mensagem
If Resposta = vbNo Then 'Se clicou no botão Não
Exit Function 'sai da rotina
Else 'senao
Kill Destino 'exclui o arquivo existente e continua a executar o codigo
End If
End If

On Error GoTo FileCopyError 'se houver erro trata aqui
F1 = FreeFile 'retorna o numero do arquivo disponivel
Open Origem For Binary As F1 'abre o arquivo de destino
F2 = FreeFile 'retorna o numero do arquivo disponivel
Open Destino For Binary As F2 'abre o arquivo de destino

FSize = LOF(F1)
BTest = FSize - LOF(F2)

Do
If BTest < BUFSIZE Then
Chunk = BTest
Else
Chunk = BUFSIZE
End If

Buf = String(Chunk, " ")
Get F1, , Buf
Put F2, , Buf
BTest = FSize - LOF(F2)

pbCopiaArquivos.Value = (100 - Int(100 * BTest / FSize)) 'avanca com a barra de progresso durante a copia

Loop Until BTest = 0
Close F1 'fecha o fonte
Close F2 'fecha o destino
CopiarArquivo = FSize

MsgBox "Arquivo copiado com sucesso.", vbInformation, "Copia com sucesso"

pbCopiaArquivos.Value = 0 'retorna a barra de progresso para o valor zero
Exit Function 'sai da rotina

FileCopyError: 'trata o erro aqui
MsgBox "Erro durante a copia...!, Tente novamente..." 'exibe mensagem de erro
Close F1 'fecha a fonte
Close F2 'fecha o destino
Exit Function 'sai da rotina

End Function

A função de suporte - ExtraiNome - que extrai o nome de um arquivo a partir de um caminho completo informado tem o seguinte código :

Public Function ExtraiNome(SpecIn As String) As String

Dim i As Integer
Dim saida As String

On Error Resume Next 'ignora qualquer erro

For i = Len(SpecIn) To 1 Step -1
If Mid(SpecIn, i, 1) = "\" Then
saida = Mid(SpecIn, i + 1) 'extrai o nome do arquivo do caminho
Exit For
End If
Next i

ExtraiNome = saida 'retorna o nome do arquivo extraido
End Function

Finalmente no evento Change da caixa de texto caminhoOrigem para habilitar a segunda caixa de texto quando algo for informado.

Private Sub caminhoOrigem_Change()

caminhoDestino.Enabled = True 'habilita a caixa de texto
procuraDestino.Enabled = True 'habilita o botão Procurar
caminhoDestino.SetFocus 'poe o cursor na caixa de texto destino

End Sub

Como o código esta todo documentado creio que não preciso dar mais detalhes.

Pegue o projeto aqui : copiaArquivos.zip   e divirta-se...

Eu sei é apenas VB, mas eu gosto...


José Carlos Macoratti