更新:November 2007
SQL Server 2008 为 varbinary(max) 列中存储的二进制 (BLOB) 数据引入了 FILESTREAM 存储属性。SQL Server 始终提供存储二进制数据的功能,但使用此功能要求进行特殊处理。非结构化的数据(例如文本文档、图像和视频)通常存储在数据库之外,从而使得难以管理此类数据。
| .gif) 说明: | 
|---|
| 您必须安装 .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 联机丛书中的以下各节中。
| 主题 | 说明 | 
|---|---|
| 提供指向 FILESTREAM 文档和相关主题的链接。 | |
| 介绍何时使用 FILESTREAM 存储以及该存储如何将 SQL Server 数据库引擎与 NTFS 文件系统集成。 | |
| 介绍如何在 SQL Server 的实例上启用 FILESTREAM,如何创建数据库和表以存储 FILESTREAM 数据以及如何操作包含 FILESTREAM 数据的行。 | |
| 介绍用于处理 FILESTREAM 数据的 Win32 API 函数。 | |
| 提供将 FILESTREAM 数据与 SQL Server 的其他功能一起使用时的注意事项、准则和限制。 |