快捷搜索:

使用SQL Server 2008的FILESTREAM特性管理文件

51CTO快译

SQL Server的FILESTREAM(文件流)特点简化了基于文件的数据(如图像)和关系数据同步的历程。

险些所有的利用法度榜样都必要某种类型的数据集,至少在检索某些数据和在用户界面中显示时要用到,平日,利用法度榜样会应用到布局化数据和非布局化数据,这样就引入了极大年夜的寻衅,你不得不在一个事务中创建、更新、删除和读取这些完全不合的数据类型,当布局化数据驻留在关系数据库中而非布局化数据却存储在文件系统中时,这个问题尤为严重。SQL Server 2008新的FILESTREAM(文件流)特点可以赞助办理这个问题,它让你可以将非布局化数据存储在文件系统中,但仍旧维持了事务的完备性,本文探究FILESTREAM(文件流)的特点和优点,以及若何运用它赞助你对非布局化数据进行更好地节制。

非布局化数据选项

在SQL Server 2005中,构建一个既依附于布局化(关系)数据有依附于非布局化(无关系)数据时,你有两个选择:

在数据库中存储布局化数据,在一个专用的存储中存储非布局化数据,如文件系统和文件办事器,虽然这种措施资源合算,但它引入了额外的繁杂度,由于你必要跨关系和非关系系统治理事务的完备性。

将布局化数据和非布局化数据都存储在数据库中,多年以来,数据库不停都支持存储非关系数据,如二进制大年夜工具,或BLOB,SQL Server称之为varbinary数据类型,虽然在数据库中存储这种数据是很方便的,但资源用度会更高,所需的磁盘空间更多,存储和检索光阴更长,对利用法度榜样的整体机能也会有负面影响。

在SQL Server 2008中,新的FILESTREAM(文件流)特点和varbinary列共同,你可以在办事器的文件系统上存储真实的数据,但可以在数据库高低文内治理和造访,这个特点让SQL Server不仅可以掩护好数据库内记录的完备性,也能够掩护好数据库记录和外部文件之间的完备性。由于这个特点是在现有的varbinary(max)数据类型之上实现的,开拓职员可以随意马虎地用上这个特点,不用对利用法度榜样的架构进行篡改。

什么时刻应用FILESTREAM(文件流)

鄙人列任一情景下你都可以斟酌应用FILESTREAM(文件流):

当你存储匀称大年夜小不低于1MB的BLOB数据类型时。

当你必要更快、只读造访来自利用法度榜样的数据时。

当你想直接从利用法度榜样的中心层代码造访BLOB时。

当你必要为单个数据库事务在数据库中存储非关系数据和关系数据时。

启用FILESTREAM(文件流)

默认环境下,FILESTREAM(文件流)特点是被禁用了的,是以在应用之前,你必须按照下面的步骤设置设置设备摆设摆设办事器和数据库实例:

1、要启用办事器实例上的FILESTREAM(文件流),打开SQL Server设置设置设备摆设摆设治理器,在SQL Server办事上点击右键,然后点击打开,你会看到一串办事器,在你想要启用FILESTREAM(文件流)的SQL Server实例上点击右键,从右键菜单中选择“属性”,切换到FILESTREAM(文件流)标签,反省“为Transact-SQL造访启用FILESTREAM(文件流)”选项,参考图1 ,你也可以在这个标签页为文件I/O流造访启用FILESTREAM(文件流)。

图1 启用FILESTREAM(文件流)-在为数据库实例设置设置设备摆设摆设应用FILESTREAM(文件流)造访之前必须为想要的SQL Server实例启用FILESTREAM(文件流)

498)this.style.width=498;'height=434 alt="" src="http://new.51cto.comhttp://www.51cto.com/files/uploadimg/20090225/1332160.jpg" width=396 border=0>

2、要为数据库实例启用FILESTREAM(文件流),履行系统存储历程sp_configure,并设置filestream_access_level参数的值为2,如下:

EXEC sp_configure filestream_access_level, 2

GO

RECONFIGURE

GO

filestream_access_level参数有效的值包括:

◆ 0 在该实例上禁用FILESTREAM(文件流),这是默认值。

◆ 1 为Transact-SQL造访启用FILESTREAM(文件流)

◆ 2 为Transact-SQL和Win32流造访启用FILESTREAM(文件流)

完成办事器和数据库实例设置设置设备摆设摆设后,接下来是创建存储数据的真实数据库,由于FILESTREAM(文件流)是专门为存储在文件系统上的二进制数据创建的,应用CREATE DATABASE语句时,专门创建一个FILEGROUP标记为流:

CREATE DATABASE FILESTREAMExample

ON

PRIMARY (

NAME = FILESTREAMExample_Primary,

FILENAME =

'c:\Projects\DevX\Data\FILESTREAMExample.mdf'),

FILEGROUP FILESTREAMGroup CONTAINSFILESTREAM (

NAME = FILESTREAMExample_FileGroup,

FILENAME = 'c:\Projects\DevX\Data\FILESTREAMExample')

LOG ON ( NAME = FILESTREAMExample_Log,

FILENAME =

'c:\Projects\DevX\Data\FILESTREAMExample.ldf')

GO

接下来,创建一个表,将它的一个列指派为VARBINARY(MAX) FILESTREAM数据类型:

CREATE TABLE Product

(

ProductID INTNOT NULLPRIMARY KEY,

Name VARCHAR(50) NOT NULL,

Picture VARBINARY(MAX) FILESTREAMNULL,

RowGuid UNIQUEIDENTIFIERNOT NULLROWGUIDCOL

UNIQUE DEFAULT NEWID()

)

GO

前面的表定义指定Picture列为varbinary(max)类型,并启用了FILESTREAM(文件流)属性,留意:凡是有FILESTREAM(文件流)列的表必须要包括一个非空独一性ROWGUID列。

所有存储在Picture列中的二进制数据都不能经由过程文件系统造访,造访这个二进制数据的独一措施是经由过程标准的CRUD (INSERT,UPDATE和 DELETE)SQL语句,下面的例子是向Product表中插入一行数据:

INSERT INTO Product VALUES(1, 'Bicycle', 0x00, default)

GO

插入的新行ProductID即是1,Name包括Bicycle,Picture列为NULL,RowGuid列包括一些默认的GUID值,现在你可以在.NET法度榜样中检索这一行,当然也可以覆盖和扩展它的内容。

应用FILESTREAM(文件流)写入数据

在这个例子中,假设用户孕育发生了一些输入,要将这些输入内容转换成字节数组,并将其存储在Product表的Picture列中,接下来创建一个Visual C#视窗利用法度榜样,命名为FileStreamExample,在新项目的默认表单上,添加一个按钮,命名为btnWriteFile,一个名叫txtInput的文本输入框(TextBox),一个命名为lstResults的列表框(ListBox),然后,在按钮上双击创建一个click事故处置惩罚器,包括清单1中的代码。

清单1 应用FILESTREAM存储数据

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

["fileStreamDB"].ConnectionString;

连接字符串存储在app.config中,如下:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<connectionStrings>

<add name="fileStreamDB"

connectionString="server=localhost\SqlServer2008;

database=FILESTREAMExample;integrated security=SSPI;

persist security info=False;"/>

</connectionStrings>

</configuration>

接下来它打开一个到数据库的连接,为SqlCommand工具分配属性值,然后以ProductID=1为前提检索Products表:

command.Connection = connection;

//从数据库获取文件的路径

command.CommandText = "SELECT Picture.PathName(), "

+ "GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Product "

+ "WHERE ProductID = 1";

这个SQL语句应用了新的函数GET_FILESTREAM_TRANSACTION_CONTEXT ()检索当前运行的会话事务,你可以绑定FILESTREAM(文件流)文件系统操作到该事务上,但这个事务必须是已经启动了的,并且也不能被非常终止或提交,当没有明确启动的事务可用的,它返回NULL值。

是以,下面的代码调用SqlConnection.BeginTransaction()措施创建一个新的SqlTransaction工具,并将其分配给SqlCommand工具:

SqlTransaction transaction =

connection.BeginTransaction(IsolationLevel.ReadCommitted);

command.Transaction = transaction;

至此,清单1启动ExecuteReader()措施履行SQL语句,履行完查询后,返回文件流的路径,并向它分配一个本地变量:

string path = reader.GetString(0);

你必要一个流写入到文件中,是以,接下来要创建一个SqlFileStream类的实例,供给路径、事务高低文、文件造访目录、文件选项一览表和分配大年夜小:

SqlFileStream stream = new SqlFileStream(path,

(byte[])reader.GetValue(1), FileAccess.Write,

FileOptions.SequentialScan, 0);

SqlFileStream类是一个新类(SQL Server 2008中才引入的),它供给了以字节序列要领造访FILESTREAM(文件流)列的措施,表1对SqlFileStream类裸露在外的属性做了一个简单的描述。

表1 SqlFileStream类属性

498)this.style.width=498;'height=153 alt="" src="http://new.51cto.comhttp://www.51cto.com/files/uploadimg/20090225/1332161.jpg" width=491 border=0>

接下来清单1开始检索用户的输入,转换成字节数组,然后写入到文件流中:

string contents = txtInput.Text;

stream.Write((System.Text.Encoding.ASCII.GetBytes(contents)), 0,

contents.Length);

stream.Close();

着末,清单1调用SqlTransaction.Commit()措施提交事务:

transaction.Commit();

以上便是往由数据库治理的启用了FILESTREAM(文件流)特点的文件的基础历程,既然已经知道若何写入FILESTREAM列,那从FILESTREAM列读取就简单了。

应用FILESTREAM读取数据

在C#项目的默认表单上,添加一个按钮,命名为btnReadFile,在click事故中插入清单2中的代码。

清单2 应用FILESTREAM读取数据。这个click事故处置惩罚法度榜样从数据库读取FILESTREAM列中的内容。

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();

}

}

为了简单起见,我只评论争论与前面不合的代码,当你创建一个SqlFileStream时,你必要指出你打开的文件流:

SqlFileStream stream = new SqlFileStream(path,

(byte[])reader.GetValue(1),FileAccess.Read,

FileOptions.SequentialScan, 0);

接下来,读取文件流的内容,转换成字节数组,再转换成字符串,着末在列表框(ListBox)中显示出来:

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);

当你运行这个利用法度榜样时,你会看到一个类似于图2的屏幕,当你点击“写入文件”按钮时,利用法度榜样把文本框(TextBox)中的内容写入到文件流中;当你点击“读取文件”按钮时,利用法度榜样从文件流读取内容,将其显示在列表框(ListBox)中。

图2 示例项目-经由过程应用SqlFileStream类读取和写入FILESTREAM列中的内容

498)this.style.width=498;'height=409 alt="" src="http://new.51cto.comhttp://www.51cto.com/files/uploadimg/20090225/1332162.jpg" width=500 border=0>

接下来的例子显示若何扩展现稀有据库中的文件流。

应用FILESTREAM追加数据

增添一个敕令按钮,命名为btnAppendFile,应用清单3中的代码作为它的click事故处置惩罚法度榜样代码。

清单3 应用FILESTREAM追加数据

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");

}

此次当你实例化SqlFileStream工具时,将文件造访权设为ReadWrite,是以你可以读取和写入文件流。

SqlFileStream stream = new SqlFileStream(path,

(byte[])reader.GetValue(1), FileAccess.ReadWrite,

FileOptions.SequentialScan, 0);

然后移动文件流的指针到文件末端,这样你就可以追加数据了:

stream.Seek(0, SeekOrigin.End);

接下来应用SqlFileStream.Write()措施将用户输入的内容写入到文件流中:

stream.Write((System.Text.Encoding.ASCII.GetBytes

(contents)), 0, contents.Length);

着末调用SqlTransaction.Commit()措施提交事务。

FILESTREAM的优点

这便是整个历程,现在你可以读取、写入和追加数据到数据库治理的文件中了,虽然这个历程可能比应用文件或在BLOB中存储数据更繁杂一些,你会发明应用数据库来治理文件由许多好处。

◆ 应用单个数据存储就可以同时造访非关系和关系数据。

◆ 在数据库备份和还原时代SQL Server自动包括非关系数据(BLOB)。

◆ 没有文件大年夜小限定,varbinary(max)数据类型最大年夜不能跨越2GB,独一受限的便是NTFS文件系统上的可用空间。

◆ 你可以在单个事务中同时插入、更新和删除关系数据和非关系数据。

◆ 应用FILESTREAM效率更高,由于SQL Server不再应用缓冲区内存操作非关系数据(BLOB)。

◆ 你可以应用ADO.NET在中心层代码直接造访非关系数据,不用再求值于自力的API了。

◆ 依附于文件大年夜小,NTFS文件系统可以比SQL Server更快地保存和检索大年夜型BLOB。

本文向你展示了若何实现新的FILESTREAM特点,正如你所看到的,当你想在一个事务中同时存储关系数据和非关系数据时,FILESTREAM供给了一个易于应用的事务编程模型。

原文:Managing Files with SQL Server 2008's FILESTREAM Feature

作者:Thiru Thangarathinam

51CTO独家译稿,相助站点转载请注明原文译者和出处为51CTO.com

您可能还会对下面的文章感兴趣: