Quantcast
Channel: CodeSection,代码区,SQL Server(mssql)数据库 技术分享 - CodeSec
Viewing all articles
Browse latest Browse all 3160

用 SQL Server 的 FileStream 实现新方式数据库存储文件

$
0
0

附件,有两种存储方式:一是以二进制存储在数据库中,二是存储在文件夹中。

法一优点是好管理,比如便于权限判断,没权限的不能读取附件,缺点是性能低下;法二是性能好,但不方便权限判断(虽然能够做到,但麻烦些)。

有没有结合二者优点的第三种方式呢?有,这在 SQL Server 2008开始就已经实现了。

第一步、启用 FileStream

在 SQL Server配置管理器/Configuration Manager中,在 SQL Server服务项中,在 SQL Server上右键,单击属性,切换到 FILESTREAM标签,勾上“针对 Transact-SQL访问启用 FILESTREAM”。如下图:


用 SQL Server 的 FileStream 实现新方式数据库存储文件

第二步、启用文件流访问级别

打开 SQL Server Management Studio,在连接上右键,单击属性,切换到高级标签,文件流访问级别中选择“已启用 Transact-SQL 访问”。如下图:


用 SQL Server 的 FileStream 实现新方式数据库存储文件

第三步、重启 SQL Server

回到 SQL Server配置管理器/Configuration Manager重启 SQL Server吧。

第四步、创建文件组

ALTER DATABASE [TestDB]
ADD FILEGROUP [FileStreamGroup] CONTAINS FILESTREAM

如果不用代码,也可在数据库上右键,单击属性,切换到文件组标签,可以看到有“行”、“文件流”两个框,在“文件流”那里添加。

第五步、创建文件

ALTER DATABASE [TestDB]
ADD FILE (NAME = N'FileStreamFile', FILENAME = N'D:\Cftea\FileStreamFile')
TO FILEGROUP [FileStreamGroup]

FILESTREAM 数据文件不能指定 SIZE、MAXSIZE 或 FILEGROWTH,所以我们只指定了 NAME、FILENAME两个 FILE参数。

在数据库上右键,单击属性,切换到文件标签,可以看到新建的文件的路径一列是:“D:\Cftea”,而不是:“D:\Cftea\FileStreamFile”,这是正常的,因为 FileStreamFile是 SQL Server管理的。

第六步、创建表

CREATE TABLE [dbo].[Files]
(
FileId UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL PRIMARY KEY,
FileContent VARBINARY(MAX) FILESTREAM NULL
) FILESTREAM_ON [FileStreamGroup]
ALTER TABLE [dbo].[Files] ADD CONSTRAINT [DF_Files_FileId] DEFAULT (newid()) FOR [FileID]

我们只指定了两个必须字段,实际运用时肯定不止这两个字段。这两个字段,一个是 UNIQUEIDENTIFIER ROWGUIDCOL,另一个是 VARBINARY(MAX) FILESTREAM。

另外,为了我们给 FileId指定了默认值 newid(),这样就不用我们在代码中为这个列指定值了,由数据库自动生成。

第七步、用 SQL保存一个文件到数据库中

using (SqlConnection conn = new SqlConnection("Data Source=.; Initial Catalog=TestDb; Integrated Security=SSPI;"))
{
conn.Open();
// 添加文件
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = "INSERT INTO Files(FileContent) VALUES(@FileContent)";
SqlParameter parameter = new SqlParameter("@FileContent", SqlDbType.VarBinary);
parameter.Value = File.ReadAllBytes("D:\\CfteaExample.jpg");
cmd.Parameters.Add(parameter);
cmd.ExecuteNonQuery();
}
conn.Close();
}

要注意的是,必须用 windows身份认证,不能用 SQL Server密码,所以连接字符串中用的是:Integrated Security=SSPI;。

保存后,我们可以发现数据库多了一条记录,但真正的文件是存储在 D:\Cftea\FileStreamFile内部中,我们可以找到一个和 CfteaExample.jpg一样大小的文件,如果我们把这个文件复制出来,加上扩展名,就可以用图片管理器打开了。

第八步、读取并输出这个图片到网页

using (SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=TestDb;Integrated Security=SSPI;")) { conn.Open();

// 读取并输出文件(以 JPG 文件输出到网页为例) using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandText = "SELECT * FROM Files"; using (SqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); byte[] bytes = new byte[3140134]; // 由于我们是测试,所以我们知道文件的实际大小,实际过程中,我们应该把这个大小记录在字段中 reader.GetBytes(1, 0, bytes, 0, bytes.Length); // 1 代表第 1 个字段,在我们这里就是 FileContent Response.ContentType = "image/jpeg"; Response.BinaryWrite(bytes); reader.Close(); } } conn.Close();

}

第九步、删除文件

using (SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=TestDb;Integrated Security=SSPI;"))
{
conn.Open();
// 清空附件(为了方便这里不是删除某一附件,而是清空所有附件)。
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = "TRUNCATE TABLE Files;CHECKPOINT;"; // TRUNCATE TABLE Files 清空表,CHECKPOINT 检查文件夹中文件如果在表中不存在,则删除文件)
cmd.ExecuteNonQuery();
}
conn.Close();
}

CHECKPOINT很重要,如果漏掉了,就只会删除记录,不会删除文件夹中的文件。

最后

怎么样,要做权限判断(有权限的人能够访问,没权限的人不能访问)就轻松多了吧,而且性能还不错。


Viewing all articles
Browse latest Browse all 3160

Trending Articles