惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
阮一峰的网络日志
阮一峰的网络日志
云风的 BLOG
云风的 BLOG
D
Docker
Vercel News
Vercel News
IT之家
IT之家
Recent Announcements
Recent Announcements
Last Week in AI
Last Week in AI
V
Visual Studio Blog
Engineering at Meta
Engineering at Meta
腾讯CDC
Google DeepMind News
Google DeepMind News
I
InfoQ
博客园 - 三生石上(FineUI控件)
Apple Machine Learning Research
Apple Machine Learning Research
The GitHub Blog
The GitHub Blog
博客园 - Franky
The Cloudflare Blog
A
About on SuperTechFans
有赞技术团队
有赞技术团队
Y
Y Combinator Blog
T
Tenable Blog
P
Proofpoint News Feed
Recorded Future
Recorded Future
Security Latest
Security Latest
H
Hackread – Cybersecurity News, Data Breaches, AI and More
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 聂微东
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Google Online Security Blog
Google Online Security Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Simon Willison's Weblog
Simon Willison's Weblog
The Last Watchdog
The Last Watchdog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
U
Unit 42
The Hacker News
The Hacker News
Martin Fowler
Martin Fowler
T
Threat Research - Cisco Blogs
NISL@THU
NISL@THU
F
Full Disclosure
M
MIT News - Artificial intelligence
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
V
V2EX
Project Zero
Project Zero

博客园 - 章立民研究室

我在點部落 笑談我的學習之路 下一代网页开发技术Silverlight——笑谈程式人生系列讲座之二 确保您的Silverlight 1.0运行时间组件是最新版本 ToolkitScriptManager VS ScriptManager 读者问与答 如何于撰写 Silverlight 1.0 的XAML时拥有Intellisense Silverlight 1.0 RC SDK 预览 新世代网站开发技术ASP .NET AJAX——章立民北京研讨会 PPT下载 新世代网站开发技术ASP .NET AJAX——章立民北京研讨会邀请函 读者询问是否一定要安装ASP.NET AJAX Extensions 答读者问 SQL Server - 请问数据库字段加密问题 读者“翔”询问如何于asp.net中删除目录 读者问与答 答读者问 Visual C# - 读者询问如何复制目录以及目录下所有的子目录与文件 Visual C# 2005 – 如何使用通配符 *.* 复制所有文件 新书出版了
SQL Server 2005 - 如何利用CLR存储过程读取与写入二进制影像数据
章立民研究室 · 2007-01-22 · via 博客园 - 章立民研究室

如何读取与写入数据库字段中的二进制影像数据是大家非常喜欢讨论的一项课题,为了顺应广大读者的要求,我们特别撰写了能够读取与写入二进制影像数据的CLR存储过程,以下我们将讨论相关的设计与使用技巧。

存取二进制影像的 CLR 存储过程位于 ReadWriteBLOB 类别库项目中,最主要的公用静态方法 ReadBlobFromDbColumn WriteBlobIntoDbColumn 分别代表读取与写入二进制数据的CLR存储过程,其用途说明如下:

q          CLR 存储过程 ReadBlobFromDbColumn 负责将字段中的二进制影像数据写出成一个 JPEG 图档。程序会根据第一个参数所指定的身份证字号搜寻「章立民研究室」数据表之数据记录,然后将该笔数据记录之「玉照」字段中的二进制影像数据写出成一个与身份证字号同名的图档(扩展名为 .jpg),并且储存至第二个参数所指定的目录中,程序代码如下所列:[Microsoft.SqlServer.Server.SqlProcedure()]
public static void ReadBlobFromDbColumn(string Id, string currentDirectory)
{
 using (SqlConnection connection =
   new SqlConnection("context connection = true"))
 {
  SqlCommand command = connection.CreateCommand();
 
  command.CommandText = "SELECT 玉照 FROM 章立民研究室 "
    + "WHERE 身份证字号 = @Id";
  command.Parameters.Add("@Id", SqlDbType.NVarChar);
  command.Parameters[0].Value = Id;
 
  // BLOB 缓冲区的大小。
  int bufferSize = 100;
 
  // BLOB byte() 缓冲区会使用 GetBytes 来填入。
  byte[] outByte = new byte[bufferSize];
 
  // GetBytes 所传回的字节。
  long retval;
 
  // 位于 BLOB 输出中的起始位置。
  long startIndex = 0;
 
  // 开启数据库连接并将数据读入数据读取器中。
  connection.Open();
  using (SqlDataReader reader =
    command.ExecuteReader(CommandBehavior.SequentialAccess))
  {
   if (reader.Read())
   {
    // FileStream 用来将 BLOB 写至一个文件(.jpg)。
    using (FileStream stream = new FileStream(
      currentDirectory + Id + ".jpg", FileMode.OpenOrCreate, FileAccess.Write))
    {
     using (BinaryWriter writer = new BinaryWriter(stream))
     {
      // 替一个新的 BLOB 重新设定起始字节。
      startIndex = 0;
     
      // 将字节读入 outByte() 并保有传回的字节数目。
      retval = reader.GetBytes(0, startIndex, outByte, 0, bufferSize);
     
      // 只有在缓冲区的大小之后还有字节就持续循环。
      while (retval == bufferSize)
      {
       writer.Write(outByte);
       writer.Flush();
      
       // 将启始索引的位置设定成最后一次缓冲区的尾端并填入缓冲区。
       startIndex += bufferSize;
       retval = reader.GetBytes(0, startIndex, outByte, 0, bufferSize);
      }
     
      // 写入剩余的字节。
      writer.Write(outByte, 0, Convert.ToInt32(retval));
      writer.Flush();
     }
    }
   }
  }
 }
}

q          CLR 存储过程 WriteBlobIntoDbColumn 负责将图文件中的二进制影像数据写回至数据库字段中。程序会根据第一个参数所指定的身份证字号搜寻「章立民研究室」数据表之数据记录,接着利用第二与第三个参数来构建出图文件的完整路径以便读取该图文件的二进制影像数据,并将其写回「玉照」字段中,兹将原始程序代码列示如下:[Microsoft.SqlServer.Server.SqlProcedure()]
public static void WriteBlobIntoDbColumn(
  string Id, string currentDirectory, string fileName)
{
 string fullFileName = currentDirectory + fileName;
 byte[] bytes = ReadFile(fullFileName);
 
 try
 {
  SqlConnection conn = new SqlConnection("context connection = true");
  conn.Open();
 
  SqlCommand sprocCommand = conn.CreateCommand();
  sprocCommand.CommandText = "dbo.usp_UpdateImage";
  sprocCommand.CommandType = CommandType.StoredProcedure;
 
  sprocCommand.Parameters.Add(new SqlParameter("@Id", SqlDbType.NVarChar));
 
  sprocCommand.Parameters[0].Value = Id;
  sprocCommand.Parameters.Add(
    new SqlParameter("@ThumbNailPhoto", SqlDbType.VarBinary));
  sprocCommand.Parameters[1].Value = bytes;
  sprocCommand.ExecuteNonQuery();
 }
 catch (SqlException e)
 {
 
 }
}

q          显然我们用于读取与写入二进制影像数据的CLR存储过程涉及到文件的存取作业,但是请注意,要让组件的程序代码能够存取文件、网络、环境变量、以及登录(Registry)等特定的外部系统资源,必须将 PERMISSION_SET 设定成 EXTERNAL_ACCESS。然而大家必须了解,拥有 UNSAFE EXTERNAL_ACCESS 权限的组件要能够在SQL Server中登录并正确运作,您必须已经设定了 TRUSTWORTHY 数据库属性或是组件已经使用非对称金钥加以签署,而且对应的登入必须具有 EXTERNAL ACCESS ASSEMBLY 权限。

在此我们是采用非对称金钥的作法,而其整体的安全性设定必须分别在类别库项目与SQL Server 2005中完成,您可以参考「SQL Server 2005完全实战」一书的说明,于此不再赘述。

q          至此,用于读取与写入二进制影像数据的 CLR 存储过程还不能使用,因为我们还必须在 SQL Server 中登录其组件并建立存储过程来参考该组件中的 CLR 存储过程。请您继续执行程序代码如下所列的SQL指令码来完成相关作业:


USE 北风贸易;
GOIF EXISTS (SELECT * FROM sys.procedures WHERE [name] =
  N'usp_UpdateImage')
DROP PROCEDURE [dbo].[usp_UpdateImage];
GOIF EXISTS (SELECT * FROM sys.procedures WHERE [name] =
  N'ReadBlobFromDbColumn')
DROP PROCEDURE [dbo].[ReadBlobFromDbColumn];
GOIF EXISTS (SELECT * FROM sys.procedures WHERE [name] =
  N'WriteBlobIntoDbColumn')
DROP PROCEDURE [dbo].[WriteBlobIntoDbColumn];
GOIF EXISTS (SELECT [name] FROM sys.assemblies WHERE [name] =
  N'ReadWriteBlob')
DROP ASSEMBLY ReadWriteBlob;
GO

-- 登录组件 ReadWriteBlob.dll
CREATE ASSEMBLY ReadWriteBlob
  FROM 'C:\SQL2005Demo\CH13\ReadWriteBLOB\
  ReadWriteBLOB\bin\ReadWriteBlob.dll'
WITH PERMISSION_SET = EXTERNAL_ACCESS;
GO-- 建立一个会参考所登录之组件ReadWriteBlob.dll
-- ReadBlobFromDbColumn的存储过程。
CREATE PROCEDURE [dbo].[ReadBlobFromDbColumn]
(
 @Id nvarchar(10),
 @CurrentDirectory nvarchar(1024)
)
AS EXTERNAL NAME
  ReadWriteBLOB.[ReadWriteBLOB.ReadWriteBlobClass].
  ReadBlobFromDbColumn;
GO-- 建立一个会参考所登录之组件ReadWriteBlob.dll
-- WriteBlobIntoDbColumn的存储过程。
CREATE PROCEDURE [dbo].[WriteBlobIntoDbColumn]
(
 @Id nvarchar(10),
 @CurrentDirectory nvarchar(1024),
 @FileName nvarchar(1024)  
)
AS EXTERNAL NAME
  ReadWriteBLOB.[ReadWriteBLOB.ReadWriteBlobClass].
  WriteBlobIntoDbColumn;
GO-- Transact-SQL存储过程会负责实际的更新作业。
CREATE PROCEDURE [dbo].[usp_UpdateImage]
  @Id nvarchar(10),
  @ThumbNailPhoto AS VARBINARY(max)
AS
BEGIN
  SET NOCOUNT ON;
 
  BEGIN TRY
    UPDATE 章立民研究室
      SET 玉照 = @ThumbNailPhoto
      WHERE 身份证字号 = @Id;
    IF(@@ROWCOUNT < 1)
      RAISERROR ('更新失败。', 16, 1);
  END TRY
  BEGIN CATCH
    SELECT
      ERROR_NUMBER() AS ErrorNumber,
       ERROR_SEVERITY() AS ErrorSeverity,
       ERROR_STATE() as ErrorState,
       ERROR_PROCEDURE() as ErrorProcedure,
       ERROR_LINE() as ErrorLine,
       ERROR_MESSAGE() as ErrorMessage;
      RAISERROR ('更新失败。', 16, 1);
  END CATCH;
END;
GO

q          我们现在终于完成了所有的前置准备工作,可以去执行 CLR 存储过程 ReadBlobFromDbColumn WriteBlobIntoDbColumn 来读取与写入二进制影像数据。如下所列之 SQL 指令码示范如何使用这两个 CLR 存储过程,存储过程执行结果如图表1所示:


USE 北风贸易;
GO-- 将身份证字号为 'A156401174' 之数据记录的「玉照」字段
-- 内容写出成 C:\Temp\A156401174.jpg
EXEC ReadBlobFromDbColumn 'A156401174', 'C:\Temp\';
GO-- 将身份证字号为 'O156405929' 之数据记录的「玉照」字段
-- 内容写出成 C:\Temp\O156405929.jpg
EXEC ReadBlobFromDbColumn 'O156405929', 'C:\Temp\';
GO-- C:\Temp\A156401174.jpg 的图档内容写回至身份证字号
-- 'A156401174' 之数据记录的「玉照」字段
EXEC WriteBlobIntoDbColumn 'A156401174', 'C:\Temp\', 'A156401174.jpg';
GO-- C:\Temp\O156405929.jpg 的图档内容写回至身份证字号
-- 'O156405929' 之数据记录的「玉照」字段
EXEC WriteBlobIntoDbColumn 'O156405929', 'C:\Temp\', 'O156405929.jpg';
GO

 

图表1

本文节录并修改自SQL Server 2005 完全实战》一书,特此声明之参考书籍:Visual C# 2005 文件 IO 与资料存取秘诀》