msdn17_capa.gif

Clique aqui para ler todos os artigos desta edição

 

Armazenando arquivos binários no SQL Server com o .Net Framework

por Giovanni Bassi

Este artigo discute

Este artigo usa as seguintes tecnologias:

·          O tipo de dados Image do SQL Server

·          As classes de serialização do .Net Framework

·          Stored Procedures no SQL Server

·          ADO.Net

SQL Server 2000, .Net Framework e VB.Net

 

Download:

SQLBin.Zip (32KB)

Chapéu

SQL Server 2000 e .Net Framework

 

 

Freqüentemente nos deparamos com a necessidade de relacionar arquivos binários a uma base de dados. Um catálogo pode conter fotos dos produtos, um gerenciador de recursos humanos pode conter fotos dos funcionários e às vezes simplesmente precisamos armazenar arquivos referentes a um processo qualquer de maneira eficiente. Esse artigo demonstrará que é possível fazer isso de forma a aproveitar toda a escalabilidade, produtividade e eficiência que já possuímos com o SQL Server e ainda ganhar na arquitetura do sistema, fazendo uso de funcionalidades disponibilizadas apenas por um Sistema Gerenciador de Banco de Dados, como a manutenção da integridade referencial e a segurança. Tudo isso utilizando somente o código gerenciado do .Net Framework, sem chamadas a APIs externas. Para isso, veremos que tipo de dados o SQL Server 2000 utiliza para armazenar dados binários extensos; veremos também como serializar e deserializar arquivos binários e por fim trabalharemos em um projeto exemplo.

 

O tipo de dados Image do SQL Server

O SQL Server armazena e gerencia dados binários como qualquer outro tipo de dados. Existe um tipo de dados no SQL Server especialmente criado para armazenar dados binários de tamanho variável. Este é o tipo de dados Image, que apesar do nome, não serve para armazenar apenas imagens, mas qualquer dado binário. O tipo Image não realiza nenhuma alteração nos dados recebidos e não diferencia os dados de acordo com a cultura do usuário se os conjuntos de caracteres utilizados forem diferentes. Isso quer dizer que, ao contrário do que acontece com o tipo de dados Text, dados salvos por um usuário na China terão exatamente a mesma interpretação quando solicitados por um usuário no Brasil, uma vez que não são traduzidos para nenhum outro conjunto de caracteres. O tipo de dados Image permite armazenar até 2 GB de dados.

Existe um mito quanto ao armazenamento de dados tão extensos no SQL Server. Teme-se que tal armazenamento afete o desempenho do banco de dados, atrapalhando as procuras e ficando no caminho dos outros dados. Isso seria uma realidade se os campos do tipo Image fossem armazenados em páginas de dados do SQL Server, o que não acontece. Tipos de dados de grande tamanho (incluídos aí também os tipos Text e nText) são armazenados em tipos de páginas diferentes das páginas de dados comuns do SQL Server. Dessa forma as procuras regulares são feitas apenas nas páginas de dados, não afetando o desempenho. Ainda assim, ambos os dados residem, a princípio, no mesmo arquivo físico de dados. Nada nos impede, no entanto, que criemos um novo grupo de arquivos para a base de dados e fazendo parte deste novo grupo um novo arquivo e associemos os campos com tipos de dados extensos a esse novo grupo. Isso também permitiria saber facilmente quanto espaço estamos alocando para esse tipo de dados.

 

Como funciona

O processo de transferência dos dados do sistema de arquivos para o SQL Server resume-se a poucas ações. Após o arquivo a ser transferido ter sido localizado ele é aberto para leitura e então serializado para um vetor de bytes. Esse vetor então é passado como parâmetro para uma stored procedure do banco de dados, que cuida de inseri-lo no devido campo de tipo Image da Base de Dados.

O processo de leitura destes dados é exatamente o inverso. Através de uma chamada SQL, lê-se a linha do SQL Server contendo o campo do tipo Image. Esse campo é passado para um vetor de bytes que é então gravado para um arquivo no sistema de arquivos do Windows.

Todo esse trabalho é dividido por dois Namespaces do .Net Framework: System.IO e System.Data.

 

O Namespace System.IO

Todo o trabalho de leitura, gravação e serialização dos arquivos é feito por classes pertencentes ao Namespace System.IO. Ele é o responsável pelas operações de entrada e saída, como por exemplo a gravação de arquivos ou a leitura da memória. Utilizaremos as classes Stream, BinaryReader e BinaryWriter para ler, gravar e serializar os arquivos a serem gravados no banco de dados.

A classe FileStream, que herda da classe base Stream, é a classe responsável pela infra-estrutura da leitura (ou gravação) dos bytes do arquivo. É ela quem abre o arquivo e realiza as operações de leitura e gravação. Esta classe possui um construtor parametrizado que permite passar o caminho do arquivo a ser aberto, facilitando muito seu trabalho de criação.

Uma maneira muito utilizada para a criação de objetos Stream com Windows Forms é através do controle OpenFileDialog. Este controle permite exibir uma caixa de diálogo para o usuário onde este escolhe o arquivo a ser aberto. Após o arquivo ter sido escolhido, utilizamos o método OpenFile deste controle para então, acessar o objeto Stream que fará a leitura do Arquivo.

Para criar objetos Stream utilizando projetos ASP.Net utilizamos o controle HTML Input File. Através deste controle o usuário é capaz de enviar arquivos ao servidor Web. Este controle possui a propriedade PostedFile, que retorna um objeto HttpPostedFile que facilita a manipulação do arquivo enviado. Este objeto, por sua vez, possui uma propriedade InputStream, que retorna um objeto HttpInputStream, do Namespace System.Web, e que também herda de Stream. É bom lembrar que o tamanho padrão máximo de upload é 4 MB, sendo possível alterar esta configuração no Web.config.

Como as classes HttpInputStream e FileStream herdam de Stream, podemos aplicar os mesmos métodos de leitura sobre elas, não fazendo diferença qual tipo específico de Stream estaremos utilizando. Nunca usaremos a classe Stream diretamente, somente classes que herdam dela, uma vez que ela é uma classe abstrata (MustInherit no VB, abstract no C#) e não pode ser instanciada diretamente. Veja alguns exemplos com a classe Stream.

 

'Utilizando o construtor parametrizado

Dim strm1 As New FileStream(txtArquivo.Text, FileMode.Open)

'Ou

Dim strm2 As New FileStream(txtArquivo.Text, FileMode.Open, FileAccess.Read, FileShare.Read) ...

Quer ler esse conteúdo completo? Tenha acesso completo