Asp.net中图片存储数据库以及页面读取显示通用方法详解-附源码下载 ...
2010-02-03 11:53 by chenkai, 1378 visits, , ,

前端碰到对在一个系统遇到流程控制中需要存储在数据库存储一个签名图片的问题-一直控制不好, 今天特别关于这个问题详细看了一下.其实这个问题网上资源还是相当多的,但问题是过于凌乱 资料残缺不全 甚至我感觉其中有相当的一部分会对读者产生一些误导.对于Asp.net中存储图片我在08年一月份就做了一个详细解决方案,今天在这个基础主要对一些细节控制上以及页面显示上做了完善,详细步骤如下:

首先声明一下开发环境:VS2008+SQL2005数据库+.NET FrameWork 3.5版本

(1)存储图片ImageStore表数据库设计:

 1 create table StoreImage
 2 (
 3    id int not null identity(1,1primary key,
 4    markname varchar(100not null,--图片备注名称
 5    markContent image not null,--文件内容
 6    markType varchar(100not null,--保存文件类型 用于生成
 7    markSize int not null,--图片长度 读取数据用
 8    markLinkUrl varchar(1000not null,--数据库路径
 9    markDate datetime not null defaultgetdate())--上传时间
10 )
11 go

 其中在表中设计中添加了上传图片文件类型和文件大小(Byte[]字节大小),主要为了读取时对图片显示进行控制.请参考后面编码说明.存储图片内容采用Image类型,SQL2005数据容量为2G,对应C#中类型Byte[](字节数组),其中在设计中我还参考使用SQL中Binary类型,但是测试后发现Binary类型容量范围1-8000字节,对于图片容量太小, markLinkUrl为了测试以图片路径方式存储并读取显示在页面这种方式 请参考后面详细说明.

(2)图片存储到数据库并单一读取:

 图片存储:通过文件上传获取图片并转换成Byte[]字节数组,保存到数据库Image字段,页面设计如下:

代码
 1 <!--说面这是全部的页面代码:-->   
 2  <form id="form1" runat="server" style="font-size:12px;" enctype="multipart/form-data">
 3     
 4      备 注:<asp:TextBox ID="markname" runat="server"></asp:TextBox>
 5      上 传:<asp:FileUpload ID="FileUpload1" runat="server" />
 6      <asp:Button ID="Button1"    runat="server"  OnClientClick="return checkClint()"   Text="上 传"    onclick="Button1_Click" />
 7      
 8      <script language="javascript" type="text/javascript">
 9        function checkClint()
10        {
11          var getmarkname=document.getElementById("markname");
12          var getfile=document.getElementById("FileUpload1");
13          
14          if(getmarkname.value=="")
15          {
16            alert('请输入图片备注名称!');
17            getmarkname.focus();
18            return false;
19          }else if(getfile.value=="")
20          {
21            alert('请选择上传文件路径!');
22            getfile.focus();
23            return false;
24          }else
25          {
26            return true;
27          }
28        } 
29      </script>
30     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
31      <asp:Button ID="Button2" runat="server" onclick="Button2_Click" Text="读取图片" />
32      
33     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
34      <asp:Button ID="Button3" runat="server" onclick="Button3_Click" Text="读取到Image控件中" />
35     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
36      <asp:Button ID="Button5" runat="server" onclick="Button5_Click"    Text="存储链接方式获取图片" />
37     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
38      <asp:Button ID="Button4" runat="server" onclick="Button4_Click" Text="下载图片" />
39      <br />
40      <br />
41      <asp:Image ID="Image1" runat="server" />
42      <br />
43      图片路径方式读取:<br />
44      服务器端:<asp:Image ID="Image2" runat="server" />
45      <br />
46      <asp:Label ID="Label2" runat="server"></asp:Label>
47      <br />
48      客户端Img:<img alt=""  runat="server" id="clintimg" />
49      <br />
50      <asp:Label ID="Label1" runat="server"></asp:Label>
51     </form>

 在页面From表单添加了一个属性-在页面Form中设置属性enctype -设置或获取表单的 MIME 编码

单一保存文件到数据库通用方法【注明:通用方法写在Button1_Click事件中-命名没有修改主要为了功能】 通用方法如下:

代码
 1         /// <summary>
 2         /// 上传文件同时并保存到数据中统一
 3         /// Author:chenkai Date:2010年2月2日16:24:29
 4         /// </summary>
 5         protected void Button1_Click(object sender, EventArgs e)
 6         {
 7             //获取数据
 8             string getname = this.markname.Text;
 9             string getfile = this.FileUpload1.PostedFile.FileName;
10 
11             //上传文件
12             string getlastpath = FileUploadCompant(this.FileUpload1);
13 
14             //获取上传文件流
15               byte[] getbyte=new byte[this.FileUpload1.PostedFile.ContentLength];
16               Stream filestream = this.FileUpload1.PostedFile.InputStream;
17              
18             //读入数据
19              filestream.Read(getbyte, 0this.FileUpload1.PostedFile.ContentLength);
20 
21             //插入数据
22              #region
23              string sql = "insert into StoreImage(markname,markContent,markType,markSize,markLinkUrl) values(@name,@content,@type,@size,@link)";
24 
25              SqlParameter[] getpars = new SqlParameter[5];
26              getpars[0= new SqlParameter("@name", getname);
27              getpars[1= new SqlParameter("@content", getbyte);//文件内容插入This.Fileupload1.FileBytes同样可以直接转换成Byte数组不用转换
28              getpars[2= new SqlParameter("@type"this.FileUpload1.PostedFile.ContentType);//保存文件类型
29              getpars[3= new SqlParameter("@size"this.FileUpload1.PostedFile.ContentLength);//文件长度
30              getpars[4= new SqlParameter("@link", getlastpath);
31 
32              int getrescount = DBUtility.SqlHelper.ExecuteNonQuery(DBUtility.SqlHelper.connString,CommandType.Text,sql,getpars);
33 
34              if (getrescount == 1)
35              {
36                  //添加成功
37                  ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "aler ""alert( '图片记录成功添加到数据库'); "true);
38              }
39              else
40              {
41                   //添加失败
42                  ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "aler ""alert( '图片记录添加失败'); "true);
43              }
44               
45              #endregion
46         }

 这种获得图片转换成Byte【】字节数组通用,注意:其中在Fileupload控件中有个GetBytes属性:This.Fileupload1.FileBytes可以直接把上传内容转换成字节数组而不必通过文件流来读取上传文件内容,这种方式更为快捷;如上图片成功保存到数据库 接下来就是如何读取和显示控制的问题:

(3)数据库存储图片的读取和显示控制:

从数据库中读取到字节流后把图片直接写入页面并对显示进行控制 读取方法如下【该方法下载Button2_Click中】:

代码
 1         /// <summary>
 2         /// 读取数据库中图片并显示出来
 3          /// Author:chenkai Date:2010年2月2日16:48:18
 4         /// </summary>
 5         protected void Button2_Click(object sender, EventArgs e)
 6         {
 7             //获得数据
 8             string sql = "select * from StoreImage order by id desc";
 9 
10              #region
11             using (SqlDataReader getreader = DBUtility.SqlHelper.ExecuteReader(DBUtility.SqlHelper.connString, CommandType.Text, sql))
12             {
13                 if (getreader != null&&getreader.HasRows)
14                 {
15                     //读取数据
16                     while (getreader.Read())
17                     {
18                         Response.ContentType = getreader["markType"as string;
19                         Response.OutputStream.Write(getreader["markContent"as byte[], 0, Convert.ToInt32(getreader["markSize"].ToString()));
20                         Response.End();
21                     }
22                 }
23             }
24              #endregion
25         }

 数据库中MarkType字段用来设置请求回发页面内容类型,获得字节流后把回发内容转换成输出流然后输出到当前页面,当然也可以直接使用Response.BinaryWrite()写入页面,图片自动显示.但是有人会说我想把它显示在页面一个Image控件中或是放到一个DIV层中这样实际需求. 这就是在实际需求对读取图片进行显示控制问题. 制作过验证码图片应该知道,验证码生成图片单独放在一个页面让后通过Image控件的ImageUrl来链接该页面,即可实现在Image控件控制,同理这种方式也是适用的: -添加了一个页面用来存储生成图片,详细代码如下:OutPutImageDemo页面后台编码:

代码
 1    //PageLoad事件中加载图片 并显示到OutPutImageDemo页面
 2    //Author:陈凯 Date:2010年2月3日10:28:17
 3    protected void Page_Load(object sender, EventArgs e)
 4         {
 5             if (!IsPostBack)
 6             {
 7                 //获得数据
 8                 string sql = "select * from StoreImage order by id desc";
 9 
10                 #region
11                 using (SqlDataReader getreader = DBUtility.SqlHelper.ExecuteReader(DBUtility.SqlHelper.connString, CommandType.Text, sql))
12                 {
13                     if (getreader != null && getreader.HasRows)
14                     {
15                         //读取数据
16                         while (getreader.Read())
17                         {
18                             Response.ContentType = getreader["markType"as string;
19                             Response.OutputStream.Write(getreader["markContent"as byte[], 0, Convert.ToInt32(getreader["markSize"].ToString()));
20                             Response.End();
21                         }
22                     }
23                 }
24                 #endregion
25             }
26         }

那么在TestImageStoreToDB.aspx页面中一个控件中获取该图片 只需设置图片的链接路径即可 代码如下:

 (4)数据库存储图片路径方式:

直接在数据库存储图片对资源图片较多, 图片文件较大 类似银行内部系统中对VIP用户签名就是用签名图片方式存储的 这主要为了安全上考虑,实际需求中使用次数频繁 且常常更新 无疑中这种使数据库中数据显得有些臃肿 数据容量增大,同时也增加了访问数据库服务器的负载,而使用存储图片路径的方式:图片文件放在服务器硬盘上,数据库中只需一个文件路径指向硬盘上图片文件即可 存储方式相比存储字节流要简单容易控制 但是我在网上发现关于这种页面显示的诸多问题如下我说明一下再Asp.net对图片页面显示控制:

数据库中存储路径为{jd1}路径: 截图如下

 

现在页面放一个服务器端的Image控件和Html中的<img/>来验证. 如果直接用{jd1}路径对控件进行赋值 页面并不显示.其实这就涉及到.net中{jd1}路径,相对路径和虚拟路径三者之间转换的问题:

{jd1}路径是不行的,在硬盘上存储文件命名是{wy}的同时不会存在不同的文件格式相同的命名情况,过滤{jd1}路径,从{jd1}路径就能看出图片的存储位置就在根目录下FileuploadDict文件夹下,我们只需把这个{jd1}路径转换成程序可用相对路径即可: 同时我们用服务器端的Image控件和Html测试一下结果:

 1             //getfilepath是获得数据中图片存储路径(markLinkUrl字段)数据
 2             if (!string.IsNullOrEmpty(getfilepath))
 3             {
 4                 //截取当前图片文件名
 5                 string getclintpath = getfilepath.Substring(getfilepath.LastIndexOf('\\'));
 6 
 7                 // 路径~/ 仅对 ASP.NET  的服务器控件起作用  ~/ 的意思是相对站点的虚拟根路径
 8                   //“~”表示的路径是当前应用程序的跟目录。“~”和上面介绍的“/”{zd0}的区别是由服务器进行动态解释
 9                 getclintpath=@"~\FileuploadDict"+getclintpath;//拼接成客户端服务器端路径
10 
11                   //设置Html中<Img/> 注意"~"对基于后台程序来动态解析的 所以Img标签 添加Runat=“Server” 在服务器端可以访问到
12                 this.clintimg.Src = getclintpath;//测试结果成功显示
13             }

来看一下对于服务器端控件页面控制显示方式:

 1        //getfilepath是从数据库获得图片存储{jd1}路径[markLinkUrl]的值  
 2        if (!string.IsNullOrEmpty(getfilepath))
 3             {
 4                 //截取文件的名称
 5                 string getclintpath = getfilepath.Substring(getfilepath.LastIndexOf('\\'));
 6 
 7                //服务器端-重置获取当前路径下服务器端虚拟应用程序根路径-成功
 8                 //使用"/"所有的路径都是从站点的跟目录开始的,例如/default.aspx指向的是localhost/default.aspx
 9                 this.Image2.ImageUrl = HttpContext.Current.Request.ApplicationPath + @"FileuploadDict" + getfilepath.Substring(getfilepath.LastIndexOf('\\'));
10               //测试结果:页面成功显示
11             }

在设置服务器端Image控件时用的是HttpContent.current.Request[获取当前请求的HttpRequest对象].ApplicationPath[获取服务器上 ASP.NET 应用程序的虚拟应用程序根路径] 来设置.我们来比对一下页面的路径:

Html中<Img/>标签: ~\FileuploadDict\2010-02-03-08-35-47rr4hnz45msimfqzh4tcdv545http_imgload6.jpg

Image服务端控件: /FileuploadDict\2010-02-03-08-35-47rr4hnz45msimfqzh4tcdv545http_imgload6.jpg

上面用的都是虚拟目录下相对路径来访问,如果直接通过拼接类似如上字符串 来对控件赋值 在Html页面时不识别的 ~/ 仅对 ASP.NET  的服务器空件起作用,.其实这就是关于Asp.net中相对路径的使用问题:处理方式如下;

(A): 如果链接中,源端点和目标端点在同一个目录下,则在链接中只需要指明目标端点的文档名称就可以了

(B):使用"/"所有的路径都是从站点的跟目录开始的,例如/default.aspx指向的是localhost/default.aspx

(C):如果在链接中,源端点和目标端点不位于同一个目录下,则只需要将目录的相对关系表达出来就可以了。如果链接指向的文档没有位于当前目录的子级目录中,则可以利用”..”符号来表示当前的父目录,多个..符号可以表示根高的父级目录,从而构建出目录的相对位置.

(D):在ASP.NET里增加了一个新的表达方法“~”,“~”表示的路径是当前应用程序的跟目录。“~”和上面介绍的“/”{zd0}的区别是由服务器进行动态解释。由于”~”是相对于应用程序的根目录,所以利用它可以简化路径的设置,在某些情况下似乎还必须使用该控件

 前面3种方法都是客户端解析的,也就是html种的源码就是这样,由浏览器来解析定向;而第四种方法是在服务器端解析,浏览器并不识别,所以常常在后台拼接时会出现字符串和服务器控件字符串相同 页面却无法显示图片问题,归咎还是Asp.net相对路径使用问题.

项目源码下载地址:[修改后下载链接-测试下载通过] 

26 条回复

  1. [楼主]  2010-02-03 11:54
    文件下载测试成功 如文件不能下载 请留言通知我 我会及时修改下载链接...
  2.  2010-02-03 12:02
    虽然简单,但楼主写的很用心,支持!
  3. [楼主]  2010-02-03 12:04
    LanceZhang
    确实是一个很简单的运用 但是我是看到网上太多了误导了 所以小结了一篇..就是把其中注意的细节说清楚
  4.  2010-02-03 12:04
    不能下载了:

    Link Information:
    All download slots for this link are currently filled.
    Please try again momentarily.

    把文件放在国外这些垃圾网盘上还不如直接传到cnblogs或者live上
  5.  2010-02-03 12:05
    up,up,up,
    好认真
  6.  2010-02-03 12:06
    就是源码下载有问题啊
  7. [楼主]  2010-02-03 12:07
    LanceZhang
    奥 是吗 刚刚测试通过了 那我修改一下下载链接...
  8.  2010-02-03 12:09
    正好对我有帮助,收藏了仔细看看,感谢了~
  9. [楼主]  2010-02-03 12:11
    LanceZhang
    刚刚测试通过了 那我修改一下链接...
  10.  2010-02-03 12:42
    image字段已经不推荐使用了,MSDN上的提示:
    在 Microsoft SQL Server 的未来版本中将删除 ntext、text 和 image 数据类型。请避免在新开发工作中使用这些数据类型,并考虑修改当前使用这些数据类型的应用程序。请改用 nvarchar(max)、varchar(max) 和 varbinary(max)。
  11.  2010-02-03 12:43
    把图片存在数据库中好像不是很好,应该存路径吧。
  12. [楼主]  2010-02-03 13:04
    jww0924
    这个倒还是没注意.. 今天听说未来的Window8操作系统中 对.NET不支持 很是不爽..
  13.  2010-02-03 13:13
    图片这么存储到数据库,做个类似kaixin001这样子的网站,那还不死翘翘啊

    window8不支持.NET,那微软{jd1}可以去死了

  14. [楼主]  2010-02-03 13:23
    卡索
    对于特殊的需求银行VIP服务的转接签名 这种还是根据需求而定 网站你要性能 那更不敢恭维了..
  15.  2010-02-03 13:50
    chenkai
    win8要不支持.net
    微软还这么费心的出.net4.0干啥...
    自己的系统都不支持
    其他平台肯定更没市场了
    那何必在费心费力出新版本

    .net花了10多年时间
    到win7才终于形成了.net的基础平台(至少原生3.5,不用再装了)
    不会这么快就放弃的...
  16.  2010-02-03 14:29
    mark
  17.  2010-02-03 14:56
    Mark!
  18.  2010-02-03 15:10
    说明一个问题是好的,实际操作中这种做法就```
  19.  2010-02-03 15:34
    只是这样做,效率会不会能保证呢?
    --
  20. [楼主]  2010-02-03 15:39
    Daan
    @Jack Niu
    这只是提供了一种方式方法. 在实际开发中根据需求来定的. 其实做法还是有很多. 看你如何选择了我只是在澄清网上关于这方面一系列有些误导的问题. 真正做选择还是你自己. 我提供自己思路只做参考...
  21. [楼主]  2010-02-03 15:39
    Daan
    想说什么? 但说无妨...
  22.  2010-02-03 21:13
    代码不能下载
  23.  2010-02-04 09:40
    不能下载。
  24.  2010-02-04 09:53
    需要交费后,才能下载
  25. [楼主]  2010-02-04 09:56
    FredTang
    好垃圾 这个当时我测试好好的 忘了 我这个朋友的号 修改一下..稍等....
  26. [楼主]  2010-02-04 10:02
    /Files/chenkai/项目编码源文件/TestNetWorkConAPI.rar
    链接已经成功修复.... 下载测试通过
郑重声明:资讯 【Asp.net中图片存储数据库以及页面读取显示通用方法详解-附源码下载 ...】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——