设为首页 收藏本站
查看: 927|回复: 0

[经验分享] 各种类型文件在SQL Server中存储的解决方案

[复制链接]

尚未签到

发表于 2015-6-30 13:15:15 | 显示全部楼层 |阅读模式
各种类型文件在SQL Server中存储的解决方案

数据的持久化是开发的基础性工作,我们不可避免要将各种的类型文件持久化,关于文件(或是大对象)的存储,我在我的blog http://www.iyunv.com/supercode/articles/156744.html谈过
今天我们从设计的角度来实现这功能,从本文中您将了解道以下内容
l         SQL Server中的数据类型
l         数据表,存储过程的设计
l         逻辑层实现各种类型文件的自动转化
l         DataGrid中的自定义文件列表显示方式,以及从服务端将文件发送客户端时的一些技巧
1. Sql server中的数据类型



DSC0000.gif Unicode 字符串
nchar
固定长度的 Unicode 数据,最大长度为 4,000 个字符。
nvarchar
可变长度 Unicode 数据,其最大长度为 4,000 字符。sysname 是系统提供用户定义的数据类型,在功能上等同于 nvarchar(128),用于引用数据库对象名。
ntext
可变长度 Unicode 数据,其最大长度为 2^30 - 1 (1,073,741,823) 个字符。
二进制字符串
binary
固定长度的二进制数据,其最大长度为 8,000 个字节。
varbinary
可变长度的二进制数据,其最大长度为 8,000 个字节。
image
可变长度的二进制数据,其最大长度为 2^31 - 1 (2,147,483,647) 个字节。

要想更加详细的数据类型请查阅Sql Server自带的帮助文件,之所以把这几个罗列出来是因为,网上很多朋友经常问到底用binary还是用image作为存储的数据类型,很显然,应该用image,因为很少有文件小于8K的,除非是网络图像(jpeg,gif,png)

2. 数据表,存储过程的设计
(1)创建表
下面是创建表的Sql


if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FileLib]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[FileLib]
GO

CREATE TABLE [dbo].[FileLib] (
       [ID] [int] IDENTITY (1, 1) NOT NULL ,
       [FName] [nvarchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,
       [FileType] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
       [FileContent] [image] NULL ,
       [FileSize] [float] NULL ,
       [FileUploader] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
       [UploadDate] [datetime] NULL ,
       [Icon] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

关系图如下


DSC0001.gif            

     图1存储文件的表
(2)创建存储过程
1.         写入数据库的存储过程


DSC0002.gif DSC0003.gif /**//************************************************************
DSC0004.gif *  Purpose: Test For UpLoad File To Sql Server                                                       *
*  Author:    登峰                                                                                                     *
*  Blog:  http://www.iyunv.com/supercode                                                             *
*  Date:       2005-6-12                                                                                             *
DSC0005.gif *****************************************************************/

CREATE proc  SetFileToDB
@_FileName  as  nvarchar(255) = null,
@_FileType  as nvarchar(50) = null,
@_FileContent as image = null,
@_FileSize as int =null,
@_FileUploader as nvarchar(50)=null,
@_UploadDate  as datetime =null,
@_Icon as nvarchar(50)=null
AS

--声明SQL变量
   declare @CreateTabSql as nvarchar(100);

--声明错误处理变量
   declare @CurrentError int



     
  --  事务开始
    BEGIN TRANSACTION
   --插入表
   insert  into FileLib(FName,FileType,FileContent,FileSize,FileUploader,UploadDate,Icon)
                               values( @_FileName,@_FileType,@_FileContent,@_FileSize,@_FileUploader,@_UploadDate,@_Icon)



   select @CurrentError = @@Error
    IF @CurrentError != 0
        BEGIN
             GOTO ERROR_HANDLER
        END
  
-- 事务结束
    COMMIT TRANSACTION

-- 成功的话返回0
    RETURN 0
  ERROR_HANDLER:
        ROLLBACK TRANSACTION
          RETURN @CurrentError
GO
3. 逻辑层实现各种类型文件的自动转化
   引用这层的目的就是简要说明一下层次的问题,本来数据层也独立出来,但这文章的目的不在于此,所以附带而过,而且这逻辑层也非常简单,为了方便起见,把相关的类和操作都放在一起文件里
(3.1)定义文件实体类


class FileEntity
    DSC0006.gif {
          private int _ID;
          private string _FileName;
          private string _FileType;
          private byte[] _FileContent;
          private int _FileSize;
          private string _FileUploader;
          private DateTime _UploadDate;
          private string _Icon;
        
DSC0007.gif DSC0008.gif         属性#region 属性

        public int ID
        {
            set{_ID=value;}
            get{ return ID;}
DSC0009.gif         }

        public string FileName
        {
            set{_FileName=value;}
            get{ return _FileName;}
        }

        public string FileType
        {
            set{_FileType=value;}
            get{ return _FileType;}
        }

        public byte[] FileContent
        {
            set{_FileContent=value;}
            get{ return _FileContent;}
        }

        public int FileSize
        {
            set{_FileSize=value;}
            get{ return _FileSize;}
        }

        public string FileUploader
        {
            set{_FileUploader=value;}
            get{ return _FileUploader;}
        }

        public DateTime UploadDate
        {
            set{_UploadDate=value;}
            get{ return _UploadDate;}
        }

        public string Icon
        {
            set{_Icon=value;}
            get{ return _Icon;}
        }

        #endregion

    }
(3.2)扩展名和图标的处理
   要想在列表里实现哪种类型的文件对应哪种图标,这需求关关联,数据库中Icon就是来保存文件的扩展名的,看下面两个处理方法


   /**////
        /// 从本地的全名路径(含文件名)中获取文件名
        ///
        /// 全名路径(含文件名)
        /// 文件名
        private string GetFileName(string path)
        {
            int index=path.LastIndexOf("\\");
            return path.Substring(index+1);

        }
        /**////
        /// 从本地的全名路径(含文件名)中获取文件的扩展名
        ///
        /// 全名路径(含文件名)
        /// 文件的扩展名
        private string  GetExteName(string path)
        {
            int index=path.LastIndexOf(".");
            return path.Substring(index+1);
        }




4. 页面的实现
4.1 页面HMTL的描述
确信你设定了Form的encType属性为multipart/form-data。显示文件列表的关键是DataGird,先看看他的描述


   
                           
                           
                           
                           
                           
                           
                                   
                                          
                                                
                                          
                                   
                                   
                                          
                                            
                                                  
                                          
                                   
                                   
                                          
                                                
                                          
                                   
                                   
                                          
                                                
                                          
                                   
                                   
                                          
                                                
                                          
                                   
                                   
                                          
                                                
                                          
                                   
                           
                     


4.2 把DB中的文件显示在DataGrid上,因为仅仅是显示,所以FileContent字段没有必要读出来,而且在这里我们自定义一个DataTable来绑定到DataGrid中,请看下面的代码


1 /**////
2        /// 从数据库中读取文件信息显示在DataGrid上
3        ///
4        private void BindGrid()
5        {
6            
7            string SelectCommand="select ID,FName,FileType,FileSize,FileUploader,UploadDate,Icon from FileLib";
8
9            SqlConnection myConnection=null;
10            try
11            {
12               myConnection = new SqlConnection(ConnectionString);
13                    myConnection.Open();
14                           
15                SqlCommand  sqlcmd=new SqlCommand(SelectCommand,myConnection);
16               
17               
18                SqlDataReader ddr=sqlcmd.ExecuteReader();
19                  
20                DataTable dt = new DataTable();
21                DataRow dr;            
22                dt.Columns.Add(new DataColumn("FileType", typeof(string)));//0
23                dt.Columns.Add(new DataColumn("FName", typeof(string)));//1
24                dt.Columns.Add(new DataColumn("FileSize", typeof(string)));//2
25                dt.Columns.Add(new DataColumn("FileUploader", typeof(string)));//3
26                dt.Columns.Add(new DataColumn("UploadDate", typeof(string)));//4
27                dt.Columns.Add(new DataColumn("Icon", typeof(string)));//5
28                 dt.Columns.Add(new DataColumn("FID", typeof(string)));//6
29                                 
30              
31                while(ddr.Read())
32                {                  
33                    dr=dt.NewRow();//新一行            
34                    dr[0]=ddr["FileType"].ToString();
35                    dr[1]=ddr["FName"].ToString();
36                    dr[2]=ddr["FileSize"].ToString();
37                    dr[3]=ddr["FileUploader"].ToString();
38                    dr[4]=ddr["UploadDate"].ToString();
39                    dr[5]=ddr["Icon"].ToString();
40                    dr[6]=ddr["ID"].ToString();
41                    dt.Rows.Add(dr);
42
43                }
44                //绑字到DataGrid
45                DataGrid1.DataSource =  new DataView(dt);
46                DataGrid1.DataBind();
47            }
48            catch (System.Exception Ex)
49            {
50                Response.Write(Ex.Message+Ex.StackTrace);
51            }
52            finally
53            {
54                myConnection.Close();
55            }
56        }
4.3 上传文件至Sql Server 数据库
     IIS对上传的大小是很限定,当然这在web.config中配置,具体的这里不详述,再查阅相关的资料,我们先把页面级的字段放在文件实体类中,再将实体类传到逻辑层来处理,三层的原理也是如此,下面是初始化提交代码

void InitEntity()
        {
            //读取相关值
            FileEntity fe=new FileEntity();         
            Stream DataStream = File1.PostedFile.InputStream; //文件流
            fe.FileSize=File1.PostedFile.ContentLength; //文件长度
            
            byte[] bdata = new byte[fe.FileSize];         
            int n = DataStream.Read(bdata,0,fe.FileSize); //全部读取缓冲,n代表实际读取字节数
            
            fe.FileContent =bdata;
            fe.FileName=GetFileName(File1.PostedFile.FileName);//全称
            fe.FileUploader=this.txtUploader.Text;         
            fe.FileType=File1.PostedFile.ContentType;
            fe.UploadDate=DateTime.Now;
            fe.Icon=GetExteName(File1.PostedFile.FileName);


            //开始写入数据库
           UpLoadFileToDB(fe);

        }


下面的代码是写入数据库的代码


/**////
        /// 上传文件至数据库
        ///
        private void UpLoadFileToDB(FileEntity fe)
        {
            SqlConnection myConnection =null;
            try
            {           
                myConnection = new SqlConnection(ConnectionString);

                SqlCommand command = new SqlCommand("SetFileToDB", myConnection);
                command.CommandType = CommandType.StoredProcedure;
        
                command.Parameters.Add("@_FileName", fe.FileName);
                command.Parameters.Add("@_FileType", fe.FileType);
                command.Parameters.Add("@_FileContent",fe.FileContent);
                command.Parameters.Add("@_FileSize", fe.FileSize);
                command.Parameters.Add("@_FileUploader", fe.FileUploader);
                command.Parameters.Add("@_UploadDate", fe.UploadDate);      
                command.Parameters.Add("@_Icon", fe.Icon);  
   
                myConnection.Open();
                int Result=command.ExecuteNonQuery();

                BindGrid();
            }
            catch(Exception ex)
            {
                Response.Write(ex.Message+ex.StackTrace);
            }
            finally
            {
                myConnection.Close();
            }            
        }
4.4 下载文件时的处理过程
当然这是也是最关键的,不然没意义了,当然这会涉及到小问题,比如,下载时的中文乱码问题,对jpeg或word文件是下载还是直接在IE中打开等问题,这些问题我都已在下面的代码中解决


/**////
        ///  将文件发给客户端,fid是本面Load时从Request读取的
        ///
        /// 文件编号
        void DownLoadFile(int fid)
        {
            SqlConnection myConnection=null;   
        
            string strDownloadSql="select FileType,FName,FileContent from FileLib where ID="+fid;

            try
            {
                myConnection    = new SqlConnection(ConnectionString);
                myConnection.Open();
                           
                SqlCommand  sqlcmd=new SqlCommand(strDownloadSql,myConnection);            
                SqlDataReader ddr=sqlcmd.ExecuteReader();
                if(ddr.Read())
                {
                     
                        Response.ContentType = ddr["FileType"].ToString();  

                        Response.AddHeader("Content-Disposition", "attachment;FileName="+HttpUtility.UrlEncode(ddr["FName"].ToString(),System.Text.Encoding.UTF8 ));

                        Response.BinaryWrite( (byte[]) ddr["FileContent"] );  
                         Response.End();

                }
               
            }

            catch(Exception ex)
            {
                Response.Write(ex.Message+ex.StackTrace);
            }
            finally
            {
                myConnection.Close();
            }
        }
好,文章到这也即将结束,最后我们来看看最终的DEMO效果 DSC00010.jpg

   

                                图2 文件上传后

下面看看下载时的效果

    DSC00011.jpg

                                                                      图3 文件下载

到此大功告成,当然您也可以在这基础之上把功能再加大,比如实现编辑,目录方式等,今天是周未,登峰祝您周未愉快!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-81952-1-1.html 上篇帖子: MS SQL Server store procedure Generator 下篇帖子: SQL Server 2005下的分页SQL
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表