Datos de FILESTREAM

Descargar ADO.NET

El atributo de almacenamiento FILESTREAM sirve para los datos binarios (BLOB) almacenados en una columna varbinary(max). Antes de FILESTREAM, el almacenamiento de datos binarios requería un tratamiento especial. Los datos no estructurados, como los documentos de texto, las imágenes y el vídeo, se suelen almacenar fuera de la base de datos, por lo que resultan difíciles de administrar.

Nota

Debe instalar .NET Framework 3.5 SP1 (o posterior) o .NET Core para trabajar con datos de FILESTREAM mediante SqlClient.

La especificación del atributo FILESTREAM en una columna varbinary(max) provoca que SQL Server almacene los datos en el sistema de archivos NTFS local en lugar de hacerlo en el archivo de base de datos. Aunque se almacenan por separado, puede usar las mismas instrucciones de Transact-SQL admitidas para trabajar con los datos varbinary(max) almacenados en la base de datos.

Compatibilidad de SqlClient con FILESTREAM

El proveedor de datos SqlClient de Microsoft para SQL Server, Microsoft.Data.SqlClient, admite la lectura y escritura en datos de FILESTREAM mediante la clase SqlFileStream definida en el espacio de nombres System.Data.SqlTypes. SqlFileStream hereda de la clase Stream, que proporciona métodos para leer y escribir en flujos de datos. Al leer de un flujo, se transfieren datos del flujo a una estructura de datos, como una matriz de bytes. Al escribir, se transfieren los datos de la estructura de datos a un flujo.

Creación de la tabla de SQL Server

Las instrucciones de Transact-SQL siguientes crean una tabla denominada employees e insertan una fila de datos. Una vez que haya habilitado el almacenamiento de FILESTREAM, puede usar esta tabla con los ejemplos de código siguientes. Al final de este artículo se encuentran los vínculos a los recursos de los Libros en pantalla de SQL Server.

CREATE TABLE employees
(
  EmployeeId INT  NOT NULL  PRIMARY KEY,
  Photo VARBINARY(MAX) FILESTREAM  NULL,
  RowGuid UNIQUEIDENTIFIER  NOT NULL  ROWGUIDCOL
  UNIQUE DEFAULT NEWID()
)
GO
Insert into employees
Values(1, 0x00, default)
GO

Ejemplo: Lectura, sobrescritura e inserción de datos de FILESTREAM

El ejemplo siguiente muestra cómo se leen datos de FILESTREAM. El código obtiene la ruta de acceso lógica al archivo, estableciendo FileAccess en Read y FileOptions en SequentialScan. A continuación, el código lee los bytes de SqlFileStream en el búfer. Los bytes se escriben luego en la ventana de la consola.

El ejemplo muestra también cómo se escriben datos en una instancia de FILESTREAM en la que se sobrescriben todos los datos existentes. El código obtiene la ruta de acceso lógica al archivo y crea SqlFileStream, estableciendo FileAccess en Write y FileOptions en SequentialScan. Un solo byte se escribe en SqlFileStream, reemplazando todos los datos del archivo.

En el ejemplo también se muestra cómo escribir datos en FILESTREAM mediante el método Seek para anexar datos al final del archivo. El código obtiene la ruta de acceso lógica al archivo y crea SqlFileStream, estableciendo FileAccess en ReadWrite y FileOptions en SequentialScan. El código usa el método Seek para buscar el final del archivo, anexando un solo byte al archivo existente.

using System;
using Microsoft.Data.SqlClient;
using System.Data.SqlTypes;
using System.Data;
using System.IO;

namespace FileStreamTest
{
    class Program
    {
        static void Main(string[] args)
        {
            SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder("server=(local);integrated security=true;Encrypt=True;database=myDB");
            ReadFileStream(builder);
            OverwriteFileStream(builder);
            InsertFileStream(builder);

            Console.WriteLine("Done");
        }

        private static void ReadFileStream(SqlConnectionStringBuilder connStringBuilder)
        {
            using (SqlConnection connection = new SqlConnection(connStringBuilder.ToString()))
            {
                connection.Open();
                SqlCommand command = new SqlCommand("SELECT TOP(1) Photo.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() FROM employees", connection);

                SqlTransaction tran = connection.BeginTransaction(IsolationLevel.ReadCommitted);
                command.Transaction = tran;

                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        // Get the pointer for the file
                        string path = reader.GetString(0);
                        byte[] transactionContext = reader.GetSqlBytes(1).Buffer;

                        // Create the SqlFileStream
                        using (Stream fileStream = new SqlFileStream(path, transactionContext, FileAccess.Read, FileOptions.SequentialScan, allocationSize: 0))
                        {
                            // Read the contents as bytes and write them to the console
                            for (long index = 0; index < fileStream.Length; index++)
                            {
                                Console.WriteLine(fileStream.ReadByte());
                            }
                        }
                    }
                }
                tran.Commit();
            }
        }

        private static void OverwriteFileStream(SqlConnectionStringBuilder connStringBuilder)
        {
            using (SqlConnection connection = new SqlConnection(connStringBuilder.ToString()))
            {
                connection.Open();

                SqlCommand command = new SqlCommand("SELECT TOP(1) Photo.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() FROM employees", connection);

                SqlTransaction tran = connection.BeginTransaction(IsolationLevel.ReadCommitted);
                command.Transaction = tran;

                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        // Get the pointer for file
                        string path = reader.GetString(0);
                        byte[] transactionContext = reader.GetSqlBytes(1).Buffer;

                        // Create the SqlFileStream
                        using (Stream fileStream = new SqlFileStream(path, transactionContext, FileAccess.Write, FileOptions.SequentialScan, allocationSize: 0))
                        {
                            // Write a single byte to the file. This will
                            // replace any data in the file.
                            fileStream.WriteByte(0x01);
                        }
                    }
                }
                tran.Commit();
            }
        }

        private static void InsertFileStream(SqlConnectionStringBuilder connStringBuilder)
        {
            using (SqlConnection connection = new SqlConnection(connStringBuilder.ToString()))
            {
                connection.Open();

                SqlCommand command = new SqlCommand("SELECT TOP(1) Photo.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() FROM employees", connection);

                SqlTransaction tran = connection.BeginTransaction(IsolationLevel.ReadCommitted);
                command.Transaction = tran;

                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        // Get the pointer for file
                        string path = reader.GetString(0);
                        byte[] transactionContext = reader.GetSqlBytes(1).Buffer;

                        using (Stream fileStream = new SqlFileStream(path, transactionContext, FileAccess.ReadWrite, FileOptions.SequentialScan, allocationSize: 0))
                        {
                            // Seek to the end of the file
                            fileStream.Seek(0, SeekOrigin.End);

                            // Append a single byte
                            fileStream.WriteByte(0x01);
                        }
                    }
                }
                tran.Commit();
            }

        }
    }
}

Para obtener otro ejemplo, vea Cómo almacenar y recuperar datos binarios en una columna de flujo de archivo.

Recursos en los Libros en pantalla de SQL Server

La documentación completa de FILESTREAM se encuentra en las secciones siguientes de los Libros en pantalla de SQL Server.

Artículo Descripción
FILESTREAM (SQL Server) Describe cuándo usar el almacenamiento de FILESTREAM y cómo se integra el motor de base de datos de SQL Server con un sistema de archivos NTFS.
Crear aplicaciones cliente para datos FILESTREAM Describe las funciones de la API de Windows para trabajar con datos FILESTREAM.
FILESTREAM y otras características de SQL Server Proporciona consideraciones, instrucciones y limitaciones para usar datos de FILESTREAM con otras características de SQL Server.

Pasos siguientes