FILESTREAM 資料

FILESTREAM 儲存體屬性適用於儲存在 varbinary(max) 資料行中的二進位 (BLOB) 資料。 在 FILESTREAM 之前,需要特殊處理才能儲存二進位資料。 非結構化資料 (例如文字文件、影像與影片) 通常會儲存在資料庫外部,因此難以管理。

注意

您必須安裝 .NET Framework 3.5 SP1 (或更新版本) 才能使用 SqlClient 來處理 FILESTREAM 資料。

針對 varbinary(max) 資料行指定 FILESTREAM 屬性會導致 SQL Server 將資料儲存在本機 NTFS 檔案系統上,而非資料庫檔案中。 雖然系統會以不同的方式儲存資料,但是您可以使用支援使用儲存在資料庫中之 varbinary(max) 資料的相同 Transact-SQL 陳述式 (Statement)。

FILESTREAM 的 SqlClient 支援

.NET Framework Data Provider for SQL Server (System.Data.SqlClient) 支援使用 System.Data.SqlTypes 命名空間中定義的 SqlFileStream 類別來讀取和寫入 FILESTREAM 資料。 SqlFileStream 繼承自 Stream 類別,其提供讀取和寫入至資料流的方法。 從資料流讀取會將資料從資料流傳輸到資料結構中,例如位元組陣列。 寫入會將資料從資料結構傳輸到資料流。

建立 SQL Server 資料表

下列 Transact-SQL 陳述式會建立名為 employees 的資料表並插入一個資料列。 一旦您啟用了 FILESTREAM 儲存體之後,就可以使用這份資料表搭配後面的程式碼範例。

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 將位元組讀取到緩衝區中。 然後,這些位元組會寫入至主控台視窗。

此範例也會示範如何將資料寫入至 FILESTREAM,以覆寫所有現有資料。 此程式碼會取得檔案的邏輯路徑,並建立 SqlFileStream,將 FileAccess 設定為 Write,將 FileOptions 設定為 SequentialScan。 單一位元組會寫入至 SqlFileStream,並取代檔案中的任何資料。

此範例還會示範如何使用 Seek 方法來附加資料至檔案的結尾,藉以將資料寫入 FILESTREAM。 此程式碼會取得檔案的邏輯路徑,並建立 SqlFileStream,將 FileAccess 設定為 ReadWrite,將 FileOptions 設定為 SequentialScan。 程式碼會使用 Seek 方法搜尋檔案結尾,並將單一位元組附加至現有的檔案。

using System;
using System.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;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();
            }

        }
    }
}

如需其他範例,請參閱如何儲存二進位資料並將其擷取至檔案資料流資料行

SQL Server 文件資源

FILESTREAM 的完整文件位於 SQL Server 文件的下列章節。

主題 說明
FILESTREAM (SQL Server) 說明使用 FILESTREAM 儲存體的時機,以及該儲存體如何將 SQL Server 資料庫引擎與 NTFS 檔案系統整合。
建立 FILESTREAM 資料的用戶端應用程式 說明用來處理 FILESTREAM 資料的 Windows API 函式。
FILESTREAM 和其他 SQL Server 功能 針對使用 FILESTREAM 資料搭配其他 SQL Server 功能提供相關的考量、指導方針和限制。

另請參閱