新聞中心
SQL Server的FILESTREAM(文件流)特性簡(jiǎn)化了基于文件的數(shù)據(jù)(如圖像)和關(guān)系數(shù)據(jù)同步的過(guò)程。

創(chuàng)新互聯(lián)專(zhuān)注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都做網(wǎng)站、網(wǎng)站制作、沈丘網(wǎng)絡(luò)推廣、微信小程序、沈丘網(wǎng)絡(luò)營(yíng)銷(xiāo)、沈丘企業(yè)策劃、沈丘品牌公關(guān)、搜索引擎seo、人物專(zhuān)訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供沈丘建站搭建服務(wù),24小時(shí)服務(wù)熱線:028-86922220,官方網(wǎng)址:www.cdcxhl.com
幾乎所有的應(yīng)用程序都需要某種類(lèi)型的數(shù)據(jù)集,至少在檢索某些數(shù)據(jù)和在用戶界面中顯示時(shí)要用到,通常,應(yīng)用程序會(huì)使用到結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù),這樣就引入了極大的挑戰(zhàn),你不得不在一個(gè)事務(wù)中創(chuàng)建、更新、刪除和讀取這些完全不同的數(shù)據(jù)類(lèi)型,當(dāng)結(jié)構(gòu)化數(shù)據(jù)駐留在關(guān)系數(shù)據(jù)庫(kù)中而非結(jié)構(gòu)化數(shù)據(jù)卻存儲(chǔ)在文件系統(tǒng)中時(shí),這個(gè)問(wèn)題尤為嚴(yán)重。SQL Server 2008新的FILESTREAM(文件流)特性可以幫助解決這個(gè)問(wèn)題,它讓你可以將非結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)在文件系統(tǒng)中,但仍然保持了事務(wù)的完整性,本文探討FILESTREAM(文件流)的特性和優(yōu)點(diǎn),以及如何運(yùn)用它幫助你對(duì)非結(jié)構(gòu)化數(shù)據(jù)進(jìn)行更好地控制。
非結(jié)構(gòu)化數(shù)據(jù)選項(xiàng)
在SQL Server 2005中,構(gòu)建一個(gè)既依賴(lài)于結(jié)構(gòu)化(關(guān)系)數(shù)據(jù)有依賴(lài)于非結(jié)構(gòu)化(無(wú)關(guān)系)數(shù)據(jù)時(shí),你有兩個(gè)選擇:
在數(shù)據(jù)庫(kù)中存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù),在一個(gè)專(zhuān)用的存儲(chǔ)中存儲(chǔ)非結(jié)構(gòu)化數(shù)據(jù),如文件系統(tǒng)和文件服務(wù)器,雖然這種方法成本合算,但它引入了額外的復(fù)雜度,因?yàn)槟阈枰珀P(guān)系和非關(guān)系系統(tǒng)管理事務(wù)的完整性。
將結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù)都存儲(chǔ)在數(shù)據(jù)庫(kù)中,多年以來(lái),數(shù)據(jù)庫(kù)一直都支持存儲(chǔ)非關(guān)系數(shù)據(jù),如二進(jìn)制大對(duì)象,或BLOB,SQL Server稱(chēng)之為varbinary數(shù)據(jù)類(lèi)型,雖然在數(shù)據(jù)庫(kù)中存儲(chǔ)這種數(shù)據(jù)是很方便的,但成本費(fèi)用會(huì)更高,所需的磁盤(pán)空間更多,存儲(chǔ)和檢索時(shí)間更長(zhǎng),對(duì)應(yīng)用程序的整體性能也會(huì)有負(fù)面影響。
在SQL Server 2008中,新的FILESTREAM(文件流)特性和varbinary列配合,你可以在服務(wù)器的文件系統(tǒng)上存儲(chǔ)真實(shí)的數(shù)據(jù),但可以在數(shù)據(jù)庫(kù)上下文內(nèi)管理和訪問(wèn),這個(gè)特性讓SQL Server不僅可以維護(hù)好數(shù)據(jù)庫(kù)內(nèi)記錄的完整性,也能夠維護(hù)好數(shù)據(jù)庫(kù)記錄和外部文件之間的完整性。因?yàn)檫@個(gè)特性是在現(xiàn)有的varbinary(max)數(shù)據(jù)類(lèi)型之上實(shí)現(xiàn)的,開(kāi)發(fā)人員可以輕易地用上這個(gè)特性,不用對(duì)應(yīng)用程序的架構(gòu)進(jìn)行改動(dòng)。
什么時(shí)候使用FILESTREAM(文件流)
在下列任一情景下你都可以考慮使用FILESTREAM(文件流):
當(dāng)你存儲(chǔ)平均大小不低于1MB的BLOB數(shù)據(jù)類(lèi)型時(shí)。
當(dāng)你需要更快、只讀訪問(wèn)來(lái)自應(yīng)用程序的數(shù)據(jù)時(shí)。
當(dāng)你想直接從應(yīng)用程序的中間層代碼訪問(wèn)BLOB時(shí)。
當(dāng)你需要為單個(gè)數(shù)據(jù)庫(kù)事務(wù)在數(shù)據(jù)庫(kù)中存儲(chǔ)非關(guān)系數(shù)據(jù)和關(guān)系數(shù)據(jù)時(shí)。
啟用FILESTREAM(文件流)
默認(rèn)情況下,F(xiàn)ILESTREAM(文件流)特性是被禁用了的,因此在使用之前,你必須按照下面的步驟配置服務(wù)器和數(shù)據(jù)庫(kù)實(shí)例:
1、要啟用服務(wù)器實(shí)例上的FILESTREAM(文件流),打開(kāi)SQL Server配置管理器,在SQL Server服務(wù)上點(diǎn)擊右鍵,然后點(diǎn)擊打開(kāi),你會(huì)看到一串服務(wù)器,在你想要啟用FILESTREAM(文件流)的SQL Server實(shí)例上點(diǎn)擊右鍵,從右鍵菜單中選擇“屬性”,切換到FILESTREAM(文件流)標(biāo)簽,檢查“為T(mén)ransact-SQL訪問(wèn)啟用FILESTREAM(文件流)”選項(xiàng),參考圖1 ,你也可以在這個(gè)標(biāo)簽頁(yè)為文件I/O流訪問(wèn)啟用FILESTREAM(文件流)。
圖1 啟用FILESTREAM(文件流)-在為數(shù)據(jù)庫(kù)實(shí)例配置使用FILESTREAM(文件流)訪問(wèn)之前必須為想要的SQL Server實(shí)例啟用FILESTREAM(文件流)
2、要為數(shù)據(jù)庫(kù)實(shí)例啟用FILESTREAM(文件流),執(zhí)行系統(tǒng)存儲(chǔ)過(guò)程sp_configure,并設(shè)置filestream_access_level參數(shù)的值為2,如下:
EXEC sp_configure filestream_access_level, 2 GO RECONFIGURE GO |
filestream_access_level參數(shù)有效的值包括:
◆ 0 在該實(shí)例上禁用FILESTREAM(文件流),這是默認(rèn)值。
◆ 1 為T(mén)ransact-SQL訪問(wèn)啟用FILESTREAM(文件流)
◆ 2 為T(mén)ransact-SQL和Win32流訪問(wèn)啟用FILESTREAM(文件流)
完成服務(wù)器和數(shù)據(jù)庫(kù)實(shí)例配置后,接下來(lái)是創(chuàng)建存儲(chǔ)數(shù)據(jù)的真實(shí)數(shù)據(jù)庫(kù),因?yàn)镕ILESTREAM(文件流)是專(zhuān)門(mén)為存儲(chǔ)在文件系統(tǒng)上的二進(jìn)制數(shù)據(jù)創(chuàng)建的,使用CREATE DATABASE語(yǔ)句時(shí),專(zhuān)門(mén)創(chuàng)建一個(gè)FILEGROUP標(biāo)記為流:
CREATE DATABASE FILESTREAMExample |
接下來(lái),創(chuàng)建一個(gè)表,將它的一個(gè)列指派為VARBINARY(MAX) FILESTREAM數(shù)據(jù)類(lèi)型:
CREATE TABLE Product |
前面的表定義指定Picture列為varbinary(max)類(lèi)型,并啟用了FILESTREAM(文件流)屬性,注意:凡是有FILESTREAM(文件流)列的表必須要包括一個(gè)非空唯一性ROWGUID列。
所有存儲(chǔ)在Picture列中的二進(jìn)制數(shù)據(jù)都不能通過(guò)文件系統(tǒng)訪問(wèn),訪問(wèn)這個(gè)二進(jìn)制數(shù)據(jù)的唯一方法是通過(guò)標(biāo)準(zhǔn)的CRUD (INSERT,UPDATE和 DELETE)SQL語(yǔ)句,下面的例子是向Product表中插入一行數(shù)據(jù):
INSERT INTO Product VALUES(1, 'Bicycle', 0x00, default) |
插入的新行ProductID等于1,Name包括Bicycle,Picture列為NULL,RowGuid列包括一些默認(rèn)的GUID值,現(xiàn)在你可以在.NET程序中檢索這一行,當(dāng)然也可以覆蓋和擴(kuò)展它的內(nèi)容。
#p#
使用FILESTREAM(文件流)寫(xiě)入數(shù)據(jù)
在這個(gè)例子中,假設(shè)用戶產(chǎn)生了一些輸入,要將這些輸入內(nèi)容轉(zhuǎn)換成字節(jié)數(shù)組,并將其存儲(chǔ)在Product表的Picture列中,接下來(lái)創(chuàng)建一個(gè)Visual C#視窗應(yīng)用程序,命名為FileStreamExample,在新項(xiàng)目的默認(rèn)表單上,添加一個(gè)按鈕,命名為btnWriteFile,一個(gè)名叫txtInput的文本輸入框(TextBox),一個(gè)命名為lstResults的列表框(ListBox),然后,在按鈕上雙擊創(chuàng)建一個(gè)click事件處理器,包括清單1中的代碼。
清單1 使用FILESTREAM存儲(chǔ)數(shù)據(jù)
private void btnWriteFile_Click(object sender, EventArgs e)
{
string connectionString =
ConfigurationManager.ConnectionStrings
["fileStreamDB"].ConnectionString;
using (SqlConnection connection = new
SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand();
command.Connection = connection;
//Get the PathName of the File from the database
command.CommandText = "SELECT Picture.PathName(), " +
"GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Product " +
"WHERE ProductID = 1";
SqlTransaction transaction = connection.BeginTransaction
(IsolationLevel.ReadCommitted);
command.Transaction = transaction;
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string path = reader.GetString(0);
SqlFileStream stream = new SqlFileStream(path,
(byte[])reader.GetValue(1), FileAccess.Write,
FileOptions.SequentialScan, 0);
string contents = txtInput.Text;
stream.Write((System.Text.Encoding.ASCII.GetBytes(contents)),
0, contents.Length);
stream.Close();
}
}
transaction.Commit();
}
MessageBox.Show("File contents successfully written");
}
它從app.config使用ConfigurationManager.ConnectionStrings屬性檢索連接字符串:
string connectionString = ConfigurationManager.ConnectionStrings |
連接字符串存儲(chǔ)在app.config中,如下:
<?xml version="1.0" encoding="utf-8" ?> |
接下來(lái)它打開(kāi)一個(gè)到數(shù)據(jù)庫(kù)的連接,為SqlCommand對(duì)象分配屬性值,然后以ProductID=1為條件檢索Products表:
command.Connection = connection; |
這個(gè)SQL語(yǔ)句使用了新的函數(shù)GET_FILESTREAM_TRANSACTION_CONTEXT ()檢索當(dāng)前運(yùn)行的會(huì)話事務(wù),你可以綁定FILESTREAM(文件流)文件系統(tǒng)操作到該事務(wù)上,但這個(gè)事務(wù)必須是已經(jīng)啟動(dòng)了的,并且也不能被異常終止或提交,當(dāng)沒(méi)有明確啟動(dòng)的事務(wù)可用的,它返回NULL值。
因此,下面的代碼調(diào)用SqlConnection.BeginTransaction()方法創(chuàng)建一個(gè)新的SqlTransaction對(duì)象,并將其分配給SqlCommand對(duì)象:
SqlTransaction transaction = |
至此,清單1啟動(dòng)ExecuteReader()方法執(zhí)行SQL語(yǔ)句,執(zhí)行完查詢后,返回文件流的路徑,并向它分配一個(gè)本地變量:
string path = reader.GetString(0); |
你需要一個(gè)流寫(xiě)入到文件中,因此,接下來(lái)要?jiǎng)?chuàng)建一個(gè)SqlFileStream類(lèi)的實(shí)例,提供路徑、事務(wù)上下文、文件訪問(wèn)目錄、文件選項(xiàng)一覽表和分配大?。?/p>
SqlFileStream stream = new SqlFileStream(path, |
SqlFileStream類(lèi)是一個(gè)新類(lèi)(SQL Server 2008中才引入的),它提供了以字節(jié)序列方式訪問(wèn)FILESTREAM(文件流)列的方法,表1對(duì)SqlFileStream類(lèi)暴露在外的屬性做了一個(gè)簡(jiǎn)單的描述。
表1 SqlFileStream類(lèi)屬性
接下來(lái)清單1開(kāi)始檢索用戶的輸入,轉(zhuǎn)換成字節(jié)數(shù)組,然后寫(xiě)入到文件流中:
string contents = txtInput.Text; |
最后,清單1調(diào)用SqlTransaction.Commit()方法提交事務(wù):
transaction.Commit(); |
以上就是往由數(shù)據(jù)庫(kù)管理的啟用了FILESTREAM(文件流)特性的文件的基本過(guò)程,既然已經(jīng)知道如何寫(xiě)入FILESTREAM列,那從FILESTREAM列讀取就簡(jiǎn)單了。
#p#
使用FILESTREAM讀取數(shù)據(jù)
在C#項(xiàng)目的默認(rèn)表單上,添加一個(gè)按鈕,命名為btnReadFile,在click事件中插入清單2中的代碼。
清單2 使用FILESTREAM讀取數(shù)據(jù)。這個(gè)click事件處理程序從數(shù)據(jù)庫(kù)讀取FILESTREAM列中的內(nèi)容。
private void btnReadFile_Click(object sender, EventArgs e)
{
string connectionString = ConfigurationManager.ConnectionStrings
["fileStreamDB"].ConnectionString;
using (SqlConnection connection = new
SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand();
command.Connection = connection;
//Get the PathName of the File from the database
command.CommandText = "SELECT Picture.PathName(), "
+ "GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Product "
+ "WHERE ProductID = 1";
SqlTransaction transaction =
connection.BeginTransaction(IsolationLevel.ReadCommitted);
command.Transaction = transaction;
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string path = reader.GetString(0);
SqlFileStream stream = new SqlFileStream(path,
(byte[])reader.GetValue(1),FileAccess.Read,
FileOptions.SequentialScan, 0);
lstResults.Items.Clear();
int length = (int) stream.Length;
byte[] contents = new byte[length];
stream.Read(contents,0,length);
string results = System.Text.Encoding.ASCII.GetString
(contents);
lstResults.Items.Add(results);
stream.Close();
}
}
transaction.Commit();
}
}
為了簡(jiǎn)單起見(jiàn),我只討論與前面不同的代碼,當(dāng)你創(chuàng)建一個(gè)SqlFileStream時(shí),你需要指出你打開(kāi)的文件流:
SqlFileStream stream = new SqlFileStream(path, |
接下來(lái),讀取文件流的內(nèi)容,轉(zhuǎn)換成字節(jié)數(shù)組,再轉(zhuǎn)換成字符串,最后在列表框(ListBox)中顯示出來(lái):
int length = (int) stream.Length; |
當(dāng)你運(yùn)行這個(gè)應(yīng)用程序時(shí),你會(huì)看到一個(gè)類(lèi)似于圖2的屏幕,當(dāng)你點(diǎn)擊“寫(xiě)入文件”按鈕時(shí),應(yīng)用程序把文本框(TextBox)中的內(nèi)容寫(xiě)入到文件流中;當(dāng)你點(diǎn)擊“讀取文件”按鈕時(shí),應(yīng)用程序從文件流讀取內(nèi)容,將其顯示在列表框(ListBox)中。
圖2 示例項(xiàng)目-通過(guò)使用SqlFileStream類(lèi)讀取和寫(xiě)入FILESTREAM列中的內(nèi)容
接下來(lái)的例子顯示如何擴(kuò)展現(xiàn)有數(shù)據(jù)庫(kù)中的文件流。
使用FILESTREAM追加數(shù)據(jù)
增加一個(gè)命令按鈕,命名為btnAppendFile,使用清單3中的代碼作為它的click事件處理程序代碼。
清單3 使用FILESTREAM追加數(shù)據(jù)
FILESTREAM.
private void btnAppendFile_Click(object sender, EventArgs e)
{
string connectionString =
ConfigurationManager.ConnectionStrings
["fileStreamDB"].ConnectionString;
using (SqlConnection connection = new
SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand();
command.Connection = connection;
//Get the PathName of the File from the database
command.CommandText = "SELECT Picture.PathName(), "
+ "GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Product "
+ "WHERE ProductID = 1";
SqlTransaction transaction =
connection.BeginTransaction(IsolationLevel.ReadCommitted);
command.Transaction = transaction;
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string path = reader.GetString(0);
SqlFileStream stream = new SqlFileStream(path,
(byte[])reader.GetValue(1), FileAccess.ReadWrite,
FileOptions.SequentialScan, 0);
stream.Seek(0, SeekOrigin.End);
string contents = txtInput.Text;
stream.Write((System.Text.Encoding.ASCII.GetBytes
(contents)), 0, contents.Length);
stream.Close();
}
}
transaction.Commit();
}
MessageBox.Show("File contents successfully appended");
}
這次當(dāng)你實(shí)例化SqlFileStream對(duì)象時(shí),將文件訪問(wèn)權(quán)設(shè)為ReadWrite,因此你可以讀取和寫(xiě)入文件流。
SqlFileStream stream = new SqlFileStream(path, |
然后移動(dòng)文件流的指針到文件末尾,這樣你就可以追加數(shù)據(jù)了:
stream.Seek(0, SeekOrigin.End); |
接下來(lái)使用SqlFileStream.Write()方法將用戶輸入的內(nèi)容寫(xiě)入到文件流中:
stream.Write((System.Text.Encoding.ASCII.GetBytes |
最后調(diào)用SqlTransaction.Commit()方法提交事務(wù)。
FILESTREAM的優(yōu)點(diǎn)
這就是全部過(guò)程,現(xiàn)在你可以讀取、寫(xiě)入和追加數(shù)據(jù)到數(shù)據(jù)庫(kù)管理的文件中了,雖然這個(gè)過(guò)程可能比使用文件或在BLOB中存儲(chǔ)數(shù)據(jù)更復(fù)雜一些,你會(huì)發(fā)現(xiàn)使用數(shù)據(jù)庫(kù)來(lái)管理文件由許多好處。
◆ 使用單個(gè)數(shù)據(jù)存儲(chǔ)就可以同時(shí)訪問(wèn)非關(guān)系和關(guān)系數(shù)據(jù)。
◆ 在數(shù)據(jù)庫(kù)備份和還原期間SQL Server自動(dòng)包括非關(guān)系數(shù)據(jù)(BLOB)。
◆ 沒(méi)有文件大小限制,varbinary(max)數(shù)據(jù)類(lèi)型最大不能超過(guò)2GB,唯一受限的就是NTFS文件系統(tǒng)上的可用空間。
◆ 你可以在單個(gè)事務(wù)中同時(shí)插入、更新和刪除關(guān)系數(shù)據(jù)和非關(guān)系數(shù)據(jù)。
◆ 使用FILESTREAM效率更高,因?yàn)镾QL Server不再使用緩沖區(qū)內(nèi)存操作非關(guān)系數(shù)據(jù)(BLOB)。
◆ 你可以使用ADO.NET在中間層代碼直接訪問(wèn)非關(guān)系數(shù)據(jù),不用再求值于獨(dú)立的API了。
◆ 依賴(lài)于文件大小,NTFS文件系統(tǒng)可以比SQL Server更快地保存和檢索大型BLOB。
本文向你展示了如何實(shí)現(xiàn)新的FILESTREAM特性,正如你所看到的,當(dāng)你想在一個(gè)事務(wù)中同時(shí)存儲(chǔ)關(guān)系數(shù)據(jù)和非關(guān)系數(shù)據(jù)時(shí),F(xiàn)ILESTREAM提供了一個(gè)易于使用的事務(wù)編程模型。
原文:Managing Files with SQL Server 2008's FILESTREAM Feature
作者:Thiru Thangarathinam
【獨(dú)家譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為.com】
【編輯推薦】
- SQL Server 2008 的恢復(fù)和備份模式
- SQL Server 2008新特性——FILESTREAM
- 視頻教程下載:SQL Server 2008 的安全性改進(jìn)
網(wǎng)站題目:使用SQLServer2008的FILESTREAM特性管理文件
網(wǎng)址分享:http://m.5511xx.com/article/cdeogih.html


咨詢
建站咨詢
