SQL Server 2008 中的 FILESTREAM 数据 (ADO.NET)

SQL Server 2008 为 varbinary(max) 列中存储的二进制 (BLOB) 数据引入了 FILESTREAM 存储属性。 SQL Server 始终提供存储二进制数据的功能,但使用此功能要求进行特殊处理。 非结构化的数据(例如文本文档、图像和视频)通常存储在数据库之外,从而使得难以管理此类数据。

注意注意

您必须安装 .NET Framework 3.5 SP1(或更高版本)才能使用 SqlClient 处理 FILESTREAM 数据。

在 varbinary(max) 列上指定 FILESTREAM 属性可使 SQL Server 将数据存储在本地 NTFS 文件系统中,而不是存储在数据库文件中。 虽然数据是单独存储的,但您可以使用所支持的用于处理存储在数据库中的 varbinary(max) 数据的相同 Transact-SQL 语句。

SqlClient 对 FILESTREAM 的支持

适用于 SQL Server 的 .NET 数据提供程序 (System.Data.SqlClient) 支持使用在 System.Data.SqlTypes 命名空间中定义的 SqlFileStream 类来读写 FILESTREAM 数据。 SqlFileStream 继承自 System.IO.Stream 类,该类提供了用于读写数据流的方法。 从流读取数据可将数据从流传输到一个数据结构,例如一个字节数组。 写入操作可将数据从该数据结构传输到一个流。

创建 SQL Server 表

下列 Transact-SQL 语句将创建一个名为 employees 的表并插入一行数据。 启用 FILESTREAM 存储之后,您可以将此表与下面的代码示例结合使用。 本主题的最后提供了指向 SQL Server 2008 联机丛书中的资源的链接。

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

读取 FILESTREAM 数据示例

下面的代码段演示如何从 FILESTREAM 读取数据。 示例代码获取文件的逻辑路径,并将 FileAccess 设置为 Read,而将 FileOptions 设置为 SequentialScan。 然后,示例代码将字节从 SqlFileStream 读入到缓存区中, 最后将这些字节写入到控制台窗口。

using (SqlConnection connection = new SqlConnection(
    connStringBuilder.ToString()))
{
    connection.Open();
    SqlCommand command = new SqlCommand("", connection);

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

    command.CommandText = 
        "select Top(1) Photo.PathName(), " 
        + "GET_FILESTREAM_TRANSACTION_CONTEXT () from employees";
    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
            FileStream fileStream = new SqlFileStream(path,
            (byte[])reader.GetValue(1),
                FileAccess.Read,
                FileOptions.SequentialScan, 0);

            // Read the contents as bytes and write them to the console
            for (long index = 0; index < fileStream.Length; index++)
            {
                Console.Write(fileStream.ReadByte());
            }
            fileStream.Close();
        }
    }
    tran.Commit();
}

覆盖 FILESTREAM 数据示例

下面的代码段演示如何将数据写入到 FILESTREAM(其中现有的所有数据将被覆盖)。 示例代码获取文件的逻辑路径,然后创建 SqlFileStream,并将 FileAccess 设置为 Write,而将 FileOptions 设置为 SequentialScan。 将一个单字节写入到 SqlFileStream,从而替换文件中的任何数据。

using (SqlConnection connection = new SqlConnection(
    connStringBuilder.ToString()))
{
    connection.Open();

    SqlCommand command = new SqlCommand("", connection);
    command.CommandText = "select Top(1) Photo.PathName(), "
    + "GET_FILESTREAM_TRANSACTION_CONTEXT () from employees";

    SqlTransaction tran = connection.BeginTransaction(
        System.Data.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
            FileStream fileStream = new SqlFileStream(path,
                (byte[])reader.GetValue(1),
                FileAccess.Write,
                FileOptions.SequentialScan, 0);

            // Write a single byte to the file. This will
            // replace any data in the file.
            fileStream.WriteByte(0x01);

            fileStream.Close();
        }
    }
    tran.Commit();
}

插入 FILESTREAM 数据示例

下面的示例演示如何通过使用 Seek 方法将数据附加到 FILESTREAM 文件的结尾,以将数据写入到其中。 示例代码获取文件的逻辑路径,然后创建 SqlFileStream,并将 FileAccess 设置为 ReadWrite,而将 FileOptions 设置为 SequentialScan。 示例代码使用 Seek 方法找到文件结尾,并将一个单字节追加到现有的文件中。

using (SqlConnection connection = new SqlConnection(
    connStringBuilder.ToString()))
{
    connection.Open();

    SqlCommand command = new SqlCommand("", connection);
    command.CommandText = "select Top(1) Photo.PathName(), "
    + "GET_FILESTREAM_TRANSACTION_CONTEXT () from employees";

    SqlTransaction tran = connection.BeginTransaction(
        System.Data.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;

            FileStream fileStream = new SqlFileStream(path,
                (byte[])reader.GetValue(1),
                FileAccess.ReadWrite,
                FileOptions.SequentialScan, 0);

            // Seek to the end of the file
            fs.Seek(0, SeekOrigin.End);

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

SQL Server 联机丛书中的资源

FILESTREAM 的完整文档位于 SQL Server 2008 联机丛书中的以下各节中。

主题

说明

Designing and Implementing FILESTREAM Storage(设计和实现 FILESTREAM 存储)

提供指向 FILESTREAM 文档和相关主题的链接。

FILESTREAM Overview(FILESTREAM 概述)

介绍何时使用 FILESTREAM 存储以及该存储如何将 SQL Server 数据库引擎与 NTFS 文件系统集成。

Getting Started with FILESTREAM Storage(FILESTREAM 存储入门)

介绍如何在 SQL Server 的实例上启用 FILESTREAM,如何创建数据库和表以存储 FILESTREAM 数据以及如何操作包含 FILESTREAM 数据的行。

Using FILESTREAM Storage in Client Applications(在客户端应用程序中使用 FILESTREAM 存储)

介绍用于处理 FILESTREAM 数据的 Win32 API 函数。

FILESTREAM and Other SQL Server Features(FILESTREAM 与其他 SQL Server 功能)

提供将 FILESTREAM 数据与 SQL Server 的其他功能一起使用时的注意事项、准则和限制。

请参见

概念

代码访问安全性和 ADO.NET

其他资源

SQL Server 数据类型和 ADO.NET

在 ADO.NET 中检索和修改数据

SQL Server 二进制和大值数据 (ADO.NET)