• 各种类型文件在SQL Server中存储的解决方案


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

    关系图如下
               

         图1存储文件的表
    (2)创建存储过程
    1.         写入数据库的存储过程
    /************************************************************
    *  Purpose: Test For UpLoad File To Sql Server                                                       *
    *  Author:    登峰                                                                                                     *
    *  Blog:  http://www.cnblogs.com/supercode                                                             *
    *  Date:       2005-6-12                                                                                             *
    *****************************************************************
    /

     
    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
        
    {
              
    private int _ID;
              
    private string _FileName;
              
    private string _FileType;
              
    private byte[] _FileContent;
              
    private int _FileSize;
              
    private string _FileUploader;
              
    private DateTime _UploadDate;
              
    private string _Icon;
            
            
    #region 属性
     
            
    public int ID
            
    {
                
    set{_ID=value;}
                
    getreturn ID;}
            }

     
            
    public string FileName
            
    {
                
    set{_FileName=value;}
                
    getreturn _FileName;}
            }

     
            
    public string FileType
            
    {
                
    set{_FileType=value;}
                
    getreturn _FileType;}
            }

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

     
            
    public int FileSize
            
    {
                
    set{_FileSize=value;}
                
    getreturn _FileSize;}
            }

     
            
    public string FileUploader
            
    {
                
    set{_FileUploader=value;}
                
    getreturn _FileUploader;}
            }

     
            
    public DateTime UploadDate
            
    {
                
    set{_UploadDate=value;}
                
    getreturn _UploadDate;}
            }

     
            
    public string Icon
            
    {
                
    set{_Icon=value;}
                
    getreturn _Icon;}
            }

     
            
    #endregion

     
        }
     
    (3.2)扩展名和图标的处理
       要想在列表里实现哪种类型的文件对应哪种图标,这需求关关联,数据库中Icon就是来保存文件的扩展名的,看下面两个处理方法
       /// <summary>
            
    /// 从本地的全名路径(含文件名)中获取文件名
            
    /// </summary>
            
    /// <param name="path">全名路径(含文件名)</param>
            
    /// <returns>文件名</returns>

            private string GetFileName(string path)
            
    {
                
    int index=path.LastIndexOf("\\");
                
    return path.Substring(index+1);
     
            }

            
    /// <summary>
            
    /// 从本地的全名路径(含文件名)中获取文件的扩展名
            
    /// </summary>
            
    /// <param name="path">全名路径(含文件名)</param>
            
    /// <returns>文件的扩展名</returns>

            private string  GetExteName(string path)
            
    {
                
    int index=path.LastIndexOf(".");
                
    return path.Substring(index+1);
            }
     
     

     
    4. 页面的实现
     4.1 页面HMTL的描述
    确信你设定了Form的encType属性为multipart/form-data。显示文件列表的关键是DataGird,先看看他的描述
       <asp:DataGrid id="DataGrid1" AutoGenerateColumns="False" style="Z-INDEX: 101; LEFT: 120px; POSITION: absolute; TOP: 88px"
                                runat
    ="server" Width="664px" Height="152px" BorderColor="#CC9966" BorderStyle="None" BorderWidth="1px"
                                BackColor
    ="White" CellPadding="4">
                                
    <FooterStyle ForeColor="#330099" BackColor="#FFFFCC"></FooterStyle>
                                
    <SelectedItemStyle Font-Bold="True" ForeColor="#663399" BackColor="#FFCC66"></SelectedItemStyle>
                                
    <ItemStyle ForeColor="#330099" BackColor="White"></ItemStyle>
                                
    <HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" BackColor="#990000"></HeaderStyle>
                                
    <PagerStyle HorizontalAlign="Center" ForeColor="#330099" BackColor="#FFFFCC"></PagerStyle>
                                
    <Columns>
                                       
    <asp:TemplateColumn HeaderText="图标">
                                              
    <ItemTemplate>
                                                     
    <img src='images/<%# (DataBinder.Eval(Container.DataItem, "Icon").ToString()) %>.gif' />
                                              
    </ItemTemplate>
                                       
    </asp:TemplateColumn>
                                       
    <asp:TemplateColumn HeaderText="文件名">
                                              
    <ItemTemplate>
                                              
    <href=WebForm1.aspx?fid=<%# DataBinder.Eval(Container.DataItem,"FID")%> > <%# DataBinder.Eval(Container.DataItem, "FName"%> </a>
                                                      
                                              
    </ItemTemplate>
                                       
    </asp:TemplateColumn>
                                       
    <asp:TemplateColumn HeaderText="内部类型">
                                              
    <ItemTemplate>
                                                     
    <asp:Label id="FileName" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "FileType") %>' />
                                              
    </ItemTemplate>
                                       
    </asp:TemplateColumn>
                                       
    <asp:TemplateColumn HeaderText="文件大小">
                                              
    <ItemTemplate>
                                                     
    <asp:Label id="FileSize" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "FileSize","{0:N}") %> '/>
                                              
    </ItemTemplate>
                                       
    </asp:TemplateColumn>
                                       
    <asp:TemplateColumn HeaderText="上传者">
                                              
    <ItemTemplate>
                                                     
    <asp:Label id="FileUploader" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "FileUploader") %> '/>
                                              
    </ItemTemplate>
                                       
    </asp:TemplateColumn>
                                       
    <asp:TemplateColumn HeaderText="上传日期">
                                              
    <ItemTemplate>
                                                     
    <asp:Label id="UploadDate" Text='<%# DataBinder.Eval(Container.DataItem, "UploadDate","{0:yyyy-MM-dd}") %>' runat="server"/>
                                              
    </ItemTemplate>
                                       
    </asp:TemplateColumn>
                                
    </Columns>
                         
    </asp:DataGrid>
     

    4.2 把DB中的文件显示在DataGrid上,因为仅仅是显示,所以FileContent字段没有必要读出来,而且在这里我们自定义一个DataTable来绑定到DataGrid中,请看下面的代码
     1 /// <summary>
     2        /// 从数据库中读取文件信息显示在DataGrid上
     3        /// </summary>

     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);
     
            }
     
    下面的代码是写入数据库的代码
     /// <summary>
            
    /// 上传文件至数据库
            
    /// </summary>

            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中打开等问题,这些问题我都已在下面的代码中解决
    /// <summary>
            
    ///  将文件发给客户端,fid是本面Load时从Request读取的
            
    /// </summary>
            
    /// <param name="fid">文件编号</param>

            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效果

     

       

                                    图2 文件上传后
     
    下面看看下载时的效果
     
        
     
                                                                          图3 文件下载
     
    到此大功告成,当然您也可以在这基础之上把功能再加大,比如实现编辑,目录方式等,今天是周未,登峰祝您周未愉快!
  • 相关阅读:
    Spring学习(九)
    NPOI的一些基本操作
    WebClient请求接口,get和post方法
    树结构关系的数据导出为excel
    AOP实践--利用MVC5 Filter实现登录状态判断
    js小结
    (转)基于http协议的api接口对于客户端的身份认证方式以及安全措施
    C# 下载文件 只利用文件的存放路径来下载
    linux nginx启动 重启 关闭命令
    两种 js下载文件的方法(转)
  • 原文地址:https://www.cnblogs.com/supercode/p/173529.html
Copyright © 2020-2023  润新知