FILESTREAM 資料
FILESTREAM 儲存體屬性適用於儲存在 varbinary(max) 資料行中的二進位 (BLOB) 資料。 在 FILESTREAM 之前,需要特殊處理才能儲存二進位資料。 非結構化資料 (例如文字文件、影像與影片) 通常會儲存在資料庫外部,因此難以管理。
注意
您必須安裝 .NET Framework 3.5 SP1 (或更新版本) 或 .NET Core,才能使用 SqlClient 來處理 FILESTREAM 資料。
針對 varbinary(max) 資料行指定 FILESTREAM 屬性會導致 SQL Server 將資料儲存在本機 NTFS 檔案系統上,而非資料庫檔案中。 雖然資料存放位置不同,但是您可以使用受支援的相同 Transact-SQL 陳述式處理儲存在資料庫中的 varbinary(max) 資料。
FILESTREAM 的 SqlClient 支援
Microsoft SqlClient Data Provider for SQL Server (Microsoft.Data.SqlClient) 支援使用 System.Data.SqlTypes 命名空間中定義的 SqlFileStream 類別來讀取和寫入 FILESTREAM 資料。 SqlFileStream
繼承自 Stream 類別,其提供讀取和寫入至資料流的方法。 從資料流讀取會將資料從資料流傳輸到資料結構中,例如位元組陣列。 寫入會將資料從資料結構傳輸到資料流。
建立 SQL Server 資料表
下列 Transact-SQL 陳述式會建立名為 employees 的資料表並插入一個資料列。 啟用 FILESTREAM 儲存體之後,您就可以使用此資料表搭配後面的程式碼範例。 《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
範例:讀取、覆寫和插入 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 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();
}
}
}
}
如需其他範例,請參閱如何儲存二進位資料並將其擷取至檔案資料流資料行。
《SQL Server 線上叢書》中的資源
FILESTREAM 的完整文件位於《SQL Server 線上叢書》中的下列章節。
發行項 | 描述 |
---|---|
FILESTREAM (SQL Server) | 說明使用 FILESTREAM 儲存體的時機,以及該儲存體如何將 SQL Server 資料庫引擎與 NTFS 檔案系統整合。 |
建立 FILESTREAM 資料的用戶端應用程式 | 說明用來處理 FILESTREAM 資料的 Windows API 函式。 |
FILESTREAM 和其他 SQL Server 功能 | 提供使用 SQL Server 其他功能處理 FILESTREAM 資料的考量、指導方針與限制。 |
後續步驟
意見反映
https://aka.ms/ContentUserFeedback。
即將推出:我們會在 2024 年淘汰 GitHub 問題,並以全新的意見反應系統取代並作為內容意見反應的渠道。 如需更多資訊,請參閱:提交及檢視以下的意見反映: