VB
.NET - Armazenando documentos em um banco de dados
Digitalizar um documento é gerar um arquivo digital que contém bytes e alguma informação sobre sua estrutura. Atualmente podemos ter uma grande variedade de documentos digitais como arquivos de imagens, documentos de texto, arquivos de áudio,etc.
Os arquivos digitais não são um problema em si mesmo, na verdade eles foram criados para ocupar menos espaço e para serem manipulados mais facilmente.
O grande problema com esses arquivos é o seu armazenamento e a sua localização. Geralmente eles acabam se espalhando de forma caótica pelo ambiente, quer em uma máquina local ou pelos servidores de uma rede, o que acaba trazendo um sério problema de localização e tratamento destes arquivos. (Nem sempre podemos compartilhar as pastas de rede)
Por que não usar então um banco de dados para armazenar os documentos digitais centralizando assim a sua localização ?
Neste arquivo eu vou mostrar como podemos armazenar documentos digitais em um banco de dados SQL Server. Vou usar a versão SQL Server 2008 Express Edition como exemplo.
No caso específico do banco de dados SQL Server temos o tipo de dados IMAGE que é um repositório para um array de bytes e que pode ser usado para armazenar e recuperar qualquer tipo de arquivo. Vamos usar esse tipo de dados em nossa tabela de exemplo.
Para realizar o armazenamento e a recuperação dos arquivos na tabela do banco de dados teremos que fazer a serialização dos mesmos que nada mais é que a transformação do conteúdo de cada arquivo em um array de bytes. Dessa forma facilitamos o transporte e a distribuição dos arquivos em uma rede quer seja local quer seja na internet.
Em nosso exemplo vamos armazenar arquivos de imagem, documentos do Word, arquivos PDF em um banco de dados SQL Server.
Os recursos usados serão:
Definindo o banco de dados e a tabela
Vamos iniciar o Visual Studio Express 2012 for Desktop e usá-lo para criar o banco de dados e a tabela usada no exemplo deste artigo.
No menu VIEW clique em Other Windows -> DataBase Explorer para abrir a DataBase Explorer exibindo as conexões existentes com as fontes de dados:
Obs: Na nova versão você já verá o novo estilo visual adotado pelo Visual Studio com a nova logomarca para refletir o design do Metro;
![]() |
Na janela DataBase Explorer clique com o botão direito do mouse sobre Data Connections e no menu suspenso clique em Add Connection...
![]() |
Na janela Add Connection, em Server Name,informe (localdb)\v11.0 e em Select or enter a database name informe o nome Gedoc que será o nome do nosso banco de dados.
Clicando no botão OK será aberta a janela informando que o banco de dados não existe e solicitando a sua confirmação para criá-lo. Clique no botão Sim:
![]() |
O Microsoft SQL
Server 2012 Express LocalDB é um modo de
execução do SQL Server Express destinado a
desenvolvedores de programas. A instalação do LocalDB copia um conjunto mínimo de arquivos necessários para iniciar o mecanismo de Banco de Dados do SQL Server. Quando o LocalDB é instalado, os desenvolvedores iniciam uma conexão usando uma cadeia de conexão especial. Na conexão, a infraestrutura necessária do SQL Server é criada e iniciada automaticamente, permitindo que o aplicativo use o banco de dados sem tarefas de configuração complexas ou demoradas. O Developer Tools pode
fornecer aos desenvolvedores um mecanismo de Banco de
Dados do SQL Server que permite que eles gravem O SQL Server Express LocalDB deve ser usado em lugar do recurso de instância de usuário do SQL Server Express, que ficou obsoleto. |
Você verá na janela DataBase Explorer a conexão com o banco de dados recém criado. Vamos criar a nossa tabela no banco de dados.
Expanda os objetos da conexão e clique com o botão direito do mouse sobre Tables;
No menu suspenso clique em Add New Table;
Na janela do descritor SQL defina a estrutura da tabela com os seguintes campos:
![]() |
Se você clicar sobre a conexão com o banco de dados Gedoc poderá ver na janela de propriedades a string de conexão definida:
![]() |
Criando o projeto no Visual Studio for Desktop
Abra o Visual Studio for Desktop e no menu File clique em New Project e selecione a linguagem Visual Basic e o template Windows Forms Application informando o nome Gedoc;
Será criada uma solução contendo o projeto Windows Forms com um formulário form1.vb e arquivo de configuração App.Config.
Altere o nome do formulário form1.vb criado para frmMenu.vb e a partir da ToolBox inclua um controle MenuStrip no formulário.
O formulário frmMenu será um container MDI e para isso vamos definir a sua propriedade IsMDIContainer como True;
A seguir vamos criar as opções do menu no formulário conforme mostra a figura a seguir:
![]() |
Na opção Salvar iremos abrir o formulário frmSalvar que permitirá ao usuário selecionar um arquivo e salvar o arquivo no banco de dados.
Na opção Exibir o formulário frmCarregar irá recuperar um documento salvo no banco de dados e conforme o seu formato exibi-lo.
A opção Sobre exibe informações da aplicação via formulário frmSobre.
Vamos criar então os três formulários que serão usados na aplicação.
No menu Project clique em Add New Item e a seguir e selecione o template Windows Forms Application.
Dessa forma crie os formulários : frmSalvar.vb , frmCarregar.vb e frmSobre.vb.
Vamos definir no arquivo App.Config a string de conexão definida para o banco de dados Gedoc conforme o código abaixo:
| <?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <configSections> </configSections> <connectionStrings> <add name="ConexaoDigital" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=Gedoc;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration> |
Vamos agora incluir um Módulo em nossa solução. No menu Project clique em Add New Item;
A seguir selecione o template Module informando o nome Geral;
![]() |
Neste módulo vamos definir 3 métodos e 1 estrutura que serão visíveis em todo projeto. Os métodos serão usados para fazer o tratamento do arquivo realizando a serialização e recuperando os bytes para exibição e a estrutura irá conter 3 propriedades que representam um documento conforme definimos na tabela Documentos:
No módulo Geral defina uma estrutura conforme o código abaixo:
| Structure Documento Public Property ID As Integer Public Property Nome As String Public Property Conteudo As Byte() End Structure |
A estrutura documento possui os campos definidos como propriedades para armazenar os dados de um documento. |
A seguir inclua o código dos 3 métodos :
Imports System.IO
Imports Gedoc.Documento
Module Geral
' Serializa o arquivo retornando array de bytes
Public Function GetBytes(ByVal _nomeArquivo As String) As Byte()
' obtém os dados do arquivo
Try
Using arquivo As New FileStream(_nomeArquivo, FileMode.Open, FileAccess.Read)
Dim br As New BinaryReader(arquivo)
Dim retorno As Byte() = br.ReadBytes(CInt(arquivo.Length))
Return retorno
End Using
Catch ex As Exception
Throw ex
End Try
End Function
' Retorna os dados do documento a partir do arquivo informado
Public Function GetDocumento(ByVal _nomeArquivo As String) As Documento
Try
' executa o método que obtém informações do arquivo
Dim documento As Documento = GetDadosArquivo(_nomeArquivo)
' serializa o arquivo
documento.Conteudo = GetBytes(_nomeArquivo)
Return documento
Catch ex As Exception
Throw ex
End Try
End Function
Private Function GetDadosArquivo(ByVal _nomeArquivo As String) As Documento
Try
' instancia o objeto de retorno, le os dados e retorna
Return New Documento() With {.Nome = _nomeArquivo}
Catch ex As Exception
Throw
End Try
End Function
|
Neste momento nossa solução terá todos itens necessários para o seu funcionamento e na janela Solution Explorer devermos ver a seguinte estrutura:
![]() |
Definindo o menu de opções
Vamos começar com o formulário frmMenu que exibir as opções da aplicação permitindo ao usuário salvar e recuperar documentos.
Inclua o código abaixo no formulário frmMenu.vb:
Public Class FrmMenu
Private Sub SalvarToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SalvarToolStripMenuItem.Click
Dim frmSalvar As New frmSalvar()
frmSalvar.MdiParent = Me
frmSalvar.Show()
End Sub
Private Sub ExibirToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExibirToolStripMenuItem.Click
Dim frmExibir As New frmCarregar()
frmExibir.MdiParent = Me
frmExibir.Show()
End Sub
Private Sub SobreToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SobreToolStripMenuItem.Click
Dim frmAbout As New frmSobre()
frmAbout.MdiParent = Me
frmAbout.Show()
End Sub
End Class
|
No código acima estamos criando uma instância do formulário que desejamos exibir e a seguir definimos qual o formulário pai desta instância definindo a propriedade MdiParent como Me. A seguir exibimos o formulário desejado.
Salvando documentos
No formulário frmSalvar.vb inclua os seguintes controles:
![]() |
Neste formulário defina as declarações dos namespaces que iremos usar :
Imports
System.Data.SqlClient
Imports System.IO
Imports System.Security
Logo após a declaração do formulário vamos definir as propriedades _conexao do tipo SqlConnection e _documento do tipo Documento:
Dim
_conexao As SqlConnection
Dim _documento As Documento
No botão btnlocalizar vamos incluir o código que permite ao usuário selecionar um documento para ser salvo no banco de dados.
Para isso vamos abrir uma janela Open File Dialog a partir da qual o usuário irá selecionar o arquivo:
Private Sub btnLocalizar_Click(sender As Object, e As EventArgs) Handles btnLocalizar.Click
'define as propriedades do controle
'OpenFileDialog
Me.ofd1.Multiselect = False
Me.ofd1.Title = "Selecionar Documento"
ofd1.InitialDirectory = "C:\dados\"
'aplica um filtro
ofd1.Filter = "Arquivos (*.PDF;*.AVI;*.MP3;*.BMP;*.JPG;*.GIF,*.PNG,*.TIFF)|*.PDF;*.AVI;*.MP3;*.BMP;*.JPG;*.GIF;*.PNG;*.TIFF|" & "Todos (*.*)|*.*"
ofd1.CheckFileExists = True
ofd1.CheckPathExists = True
ofd1.FilterIndex = 2
ofd1.RestoreDirectory = True
Dim dr As DialogResult = Me.ofd1.ShowDialog()
If dr = System.Windows.Forms.DialogResult.OK Then
If String.IsNullOrEmpty(ofd1.FileName) Then
Return
End If
Try
txtDocumento.Text += ofd1.FileName
'define os dados do documento
_documento = GetDocumento(ofd1.FileName)
_documento.Conteudo = GetBytes(ofd1.FileName)
_documento.Nome = txtDocumento.Text
btnSalvar.Enabled = True
Catch ex As SecurityException
' O usuário não possui permissão para ler arquivos
MessageBox.Show((("Erro de segurança Contate o administrador de segurança da rede." &
vbLf & vbLf & "Mensagem : ") + ex.Message &
vbLf & vbLf & "Detalhes (enviar ao suporte):" & vbLf & vbLf) + ex.StackTrace)
Catch ex As Exception
' Não pode carregar a imagem (problemas de permissão)
MessageBox.Show(("Não é possível exibir a imagem : " &
ofd1.FileName & ". Você pode não ter permissão para ler o arquivo , ou " _
& " ele pode estar corrompido." & vbLf & vbLf & "Erro reportado : ") + ex.Message)
End Try
End If
End Sub
|
Após selecionar o arquivo e obter os dados documento o usuário deverá clicar no botão Salvar para armazenar o documento no banco de dados. O código deste botão é visto abaixo:
Private Sub btnSalvar_Click(sender As Object, e As EventArgs) Handles btnSalvar.Click
SalvarDocumento()
End Sub
Public Sub SalvarDocumento()
' Cria o comando SQL
Dim commandString As String = "INSERT INTO Documentos (Nome,Conteudo) VALUES (@Nome, @Conteudo)"
' define a string de conexão com o banco de dados
_conexao = New SqlConnection("Data Source=(localdb)\v11.0;Initial Catalog=Gedoc;Integrated Security=True")
Try
'Abre a conexão com o banco de dados
_conexao.Open()
Dim command As New SqlCommand(commandString, _conexao)
' adiciona os parâmetros
command.Parameters.AddWithValue("Nome", _documento.Nome)
command.Parameters.AddWithValue("Conteudo", _documento.Conteudo)
' Grava o documento no banco de dados
command.ExecuteNonQuery()
MessageBox.Show("Arquivo salvo com sucesso no banco de dados !")
btnSalvar.Enabled = False
Catch ex As Exception
Throw ex
Finally
_conexao.Close()
End Try
End Sub
|
Recuperando documentos
No formulário frmCarregar.vb iremos recuperar e exibir um documento armazenado no banco de dados.
Para facilitar a vida do usuário vamos exibir o conteúdo da tabela Documentos em um controle DataGridView de forma que o usuário poderá selecionar uma linha do controle e o nome do arquivo será exibido em um TextBox(txt.
Clicando no botão Exibir iremos verificar o formato do arquivo e se o mesmo for um arquivo de imagem iremos exibi-lo em um controle PictureBox e se form de outro formato iremos abrir o documento usando a classe Process do namespace System.Diagnostics.
Usando a classe Process você pode obter informações sobre processos e aplicações , pode também usá-la para criar uma instância de uma aplicação ou parar um processo que esta sendo executado. A grosso modo poderíamos dizer que a classe Process é a sucessora do comando Shell do VB6 (lembra dele ?)
Vamos incluir no formulário frmCarregar os seguintes controles:
Conforme o leiaute abaixo:
![]() |
Vamos declara os namespaces usados no formulário:
Imports
System.Data.SqlClient
Imports System.IO
Imports System.IO.File
Imports System.Diagnostics
No início do formulário vamos declarar as variáveis para tratar a conexão e o documento:
Dim
_conexao As SqlConnection
Dim _documento As Documento
No evento Load do formulário temos o código que acessa a tabela Documentos e exibe os dados no controle DataGridView:
Private Sub frmCarregar_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
' cria comando SQL
Dim commandString As String = "Select id, nome from Documentos"
' Cria conexao com o banco de dados
_conexao = New SqlConnection("Data Source=(localdb)\v11.0;Initial Catalog=Gedoc;Integrated Security=True")
Dim command As New SqlCommand(commandString, _conexao)
' Cria um dataAdapter
Dim adapter As New SqlDataAdapter(command)
' preenche o DataTable.
Dim dataTable As New DataTable()
'exibe os documentos no datagridview
adapter.Fill(dataTable)
dgvDocumentos.DataSource = dataTable
Catch ex As Exception
Throw ex
Finally
_conexao.Close()
End Try
End Sub
|
No evento CellEnter do datagridview temos o código que obtém o nome e o local do documento e o código do documento exibindo-os nos controles do formulário:
Private Sub dgvDocumentos_CellEnter(sender As Object, e As DataGridViewCellEventArgs) Handles dgvDocumentos.CellEnter
'obtem o valor da primeira e segunda colunas da célula selecionada e atribui ao textbox e label no formulario
txtDocumento.Text = dgvDocumentos.Rows(e.RowIndex).Cells(1).Value().ToString
lblID.Text = dgvDocumentos.Rows(e.RowIndex).Cells(0).Value().ToString
End Sub
|
No botão Exibir recuperamos o documento e exibimos o seu conteúdo:
Private Sub btnExibir_Click(sender As Object, e As EventArgs) Handles btnExibir.Click
Try
_documento = New Documento
_documento.Conteudo = RecuperarDocumento()
'obtem a extensão do arquivo
Dim fInfo As New FileInfo(txtDocumento.Text)
Dim extensao As String = fInfo.Extension
' cria um objeto MemoryStream a partir dos dados do documento
Dim novoStream As New MemoryStream(_documento.Conteudo)
'define as extensões para imagem
Dim Extensoes As New List(Of String)(New String() {".jpg", ".bmp", ".png", ".gif"})
'verifica se a extensão é de uma formato de imagem e exige a imagem
If Extensoes.Contains(extensao) Then
picDocumento.Image = System.Drawing.Image.FromStream(novoStream)
picDocumento.SizeMode = PictureBoxSizeMode.StretchImage
Else
Using fs As New FileStream(txtDocumento.Text, FileMode.OpenOrCreate, FileAccess.Write)
fs.Write(_documento.Conteudo, 0, _documento.Conteudo.Length)
fs.Flush()
fs.Close()
End Using
Process.Start(txtDocumento.Text)
End If
Catch ex As Exception
Throw ex
End Try
End Sub
|
O código que usamos para exibir um documento que não é uma imagem é :
Using fs As
New FileStream(txtDocumento.Text, FileMode.OpenOrCreate,
FileAccess.Write)
fs.Write(_documento.Conteudo, 0,
_documento.Conteudo.Length)
fs.Flush()
fs.Close()
End Using
Process.Start(txtDocumento.Text)
A classe Process inicia o aplicativo associado ao tipo de documento armazenado permitindo que seja exibido os mais diversos tipos de documentos.
A rotina RecuperarDocumento() obtém o conteúdo do documento armazenado como um array de bytes a partir do seu código:
Public Function RecuperarDocumento() As Byte()
Try
' cria um comando SQL filtrando pelo numero de codigo (Id) do documento
Dim commandString As String = "Select conteudo from Documentos where id = " & Convert.ToInt32(lblID.Text)
' Cria uma conexão com o banco de dados
_conexao = New SqlConnection("Data Source=(localdb)\v11.0;Initial Catalog=Gedoc;Integrated Security=True")
Dim command As New SqlCommand(commandString, _conexao)
' Cria um data adapter.
Dim adapter As New SqlDataAdapter(command)
' preenche um DataTable.
Dim dataTable As New DataTable()
adapter.Fill(dataTable)
' verifica se existem registros no banco de dados com o criterio
If dataTable.Rows.Count > 0 Then
' O documento esta armazenado na forma de bytes na coluna conteudo
' Retorna esses bytes do primeiro registro encontrado para um novo buffer.
Dim buffer() As Byte = CType(dataTable.Rows(0)("Conteudo"), Byte())
Return buffer
Else
MessageBox.Show("Arquivo não localizado!")
Return Nothing
End If
Catch ex As Exception
Throw ex
Finally
_conexao.Close()
End Try
End Function
|
Abaixo vemos o projeto em execução:
![]() |
O objetivo básico do artigo foi cumprido : mostrei como podemos armazenar e recuperar documentos em um banco de dados.
A forma de implementação usada não esta aderente às boas práticas e precisa ser melhorada. Temos que separar responsabilidades, evitar código duplicado, facilitar a manutenção, etc.
Em outro artigo eu pretendo mostrar como podemos ajustar a aplicação ajustando às boas práticas de programação com aplicação de conceitos básicos da orientação a objetos, sim porque neste estágio estamos longe de ter uma aplicação OOP.
Pegue o projeto completo
aqui:
Gedoc.zip
Mateus 8: 20 Respondeu-lhe Jesus: As raposas têm covis, e as aves do céu têm ninhos; mas o Filho do homem não tem onde reclinar a cabeça.
João 2:6
“Aquele que diz que permanece nele, esse deve também andar assim como ele andou”1 Pedro 2:11 “Amados, exorto-vos, como peregrinos e forasteiros que sois, a vos absterdes das paixões carnais, que fazem guerra contra a alma.”
Efésios 4:1-2 - “Rogo-vos, pois, eu, o prisioneiro no Senhor, que andeis de modo digno da vocação a que fostes chamados, como toda a humildade e mansidão, com longanimidade, suportando-vos uns aos outros em amor.”
Efésios 5:8 - Pois, outrora, éreis trevas, porém, agora, sois luz no Senhor; andai como filhos da luz.”
Jesus não teve nenhum bem terreno, não procurou ajuntar riqueza nessa terra; devemos andar como ele andou, como peregrinos e forasteiros nesta terra com humildade e mansidão. Muito diferente do que vemos espalhado por ai sendo propalado pelos falsos profetas e homens cheios de ganância que só pensam nas coisas dessa terra e deturpam a palavra da verdade.
Referências: