ASP.NET初学笔记:FileUpload控件

  • FileUpLoad控件用于用户向Web应用程序上传文件。文件上传后,可以把文件保存在任意地方,通常把文件保存在文件系统或数据库。向页面 添加FileUpLoad控件会自动地为服务器的<form>标签添加enctype="multipart/form-data"属性。

1.  把文件保存到文件系统

  • 以下代码页面展示了如何使用FileUpLoad控件把图片上传到应用程序。
    [c-sharp] view plaincopy
    1. <%@ Page Language="C#" %>  
    2. <%@ Import Namespace="System.IO" %>  
    3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
    4. <script runat="server">  
    5.     protected void btnAdd_Click(object sender, EventArgs e)  
    6.     {  
    7.         if (upImage.HasFile)  
    8.         {  
    9.             if (CheckFileType(upImage.FileName))  
    10.             {  
    11.                 //用FileUpload.FileName属性得到上传文件名,也可以使用HttpPostedFile.FileName得到。  
    12.                 string filePath = "~/UploadImages/" + upImage.FileName;  
    13.                 //MapPath方法,检索虚拟路径(绝对的或相对的)或应用程序相关的路径映射到的物理路径。  
    14.                 //FileUpload.SavaAs()方法用于把上传文件保存到文件系统中,也可以使用HttpPostedFile.SaveAs()方法。  
    15.                 upImage.SaveAs(MapPath(filePath));  
    16.             }  
    17.         }  
    18.     }  
    19.     bool CheckFileType(string fileName)  
    20.     {  
    21.         //GetExtension()方法返回指定的路径字符串的扩展名。  
    22.         //Path类位于System.IO命名空间中,用于对包含文件或目录路径信息的 String 实例执行操作。  
    23.         string ext = Path.GetExtension(fileName);  
    24.         switch (ext.ToLower())  
    25.         {  
    26.             case ".gif"return true;  
    27.             case ".png"return true;  
    28.             case ".jpg"return true;  
    29.             case ".jpeg"return true;  
    30.             defaultreturn false;  
    31.         }  
    32.     }  
    33.     void Page_PreRender()  
    34.     {  
    35.         string upFolder = MapPath("~/UploadImages/");  
    36.         //在指定的路径中初始化DirectoryInfo类的新实例,DirectoryInfo类公开用于创建、移动和枚举目录和子目录的实例方法。  
    37.         DirectoryInfo dir = new DirectoryInfo(upFolder);  
    38.         //GetFiles,返回当前目录的文件列表。  
    39.         dlstImages.DataSource = dir.GetFiles();  
    40.         dlstImages.DataBind();  
    41.     }  
    42. </script>  
    43.   
    44. <html xmlns="http://www.w3.org/1999/xhtml">  
    45. <head runat="server">  
    46.     <title>无标题页</title>  
    47. </head>  
    48. <body>  
    49.     <form id="form1" runat="server">  
    50.     <div>  
    51.         <asp:Label ID="lblImageFile" runat="server" Text="Image File" AssociatedControlID="upImage"></asp:Label>  
    52.         <asp:FileUpload ID="upImage" runat="server" /><br />  
    53.         <asp:Button ID="btnAdd" runat="server" Text="Add Image" OnClick="btnAdd_Click"/><hr />  
    54.         <asp:DataList ID="dlstImages" RepeatColumns="3" runat="server">  
    55.             <ItemTemplate>  
    56.                 <asp:Image ID="Image1" runat="server" style="width:200px"  
    57.                     ImageUrl='<%# Eval("Name","~/UploadImages/{0}") %>' />  
    58.                  <br />  
    59.                  <%# Eval("Name") %>  
    60.                  <!--Name,对于文件,获取该文件的名称。对于目录,如果存在层次结构,则获取层次结构中最后一个目录的名称。否则,Name 属性获取该目录的名称。 -->  
    61.             </ItemTemplate>  
    62.         </asp:DataList>  
    63.     </div>  
    64.     </form>  
    65. </body>  
    66. </html>  
    效果:

    为在系统中保存文件,asp.net页面关联的Windows帐户必须有足够的权限来保存文件。

2.  把文件保存到数据库

  • 也可以用FileUpload控件把文件保存到数据库表。在数据库中保存和检索文件会给服务器增加更多压力。但是它也有些优点,首先,可以避免系统权限问题,其次,能更方便地备份信息。下面演示的是如何把Word文档保存到数据库表中。
    [c-sharp] view plaincopy
    1. <%@ Page Language="C#" %>  
    2. <%@ Import Namespace="System.IO" %>  
    3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
    4.   
    5. <script runat="server">  
    6.     protected void btnAdd_Click(object sender, EventArgs e)  
    7.     {  
    8.         if (upFile.HasFile)  
    9.         {  
    10.             //调用SqlDataSource控件的Insert()方法把FileUpLoad控件的FileName和FileBytes属性的值插入本地SQL Express数据库表。  
    11.             //Insert()方法使用InsertCommand SQL字符串和InsertParameters集合中的所有参数执行插入操作。  
    12.             if (CheckFileType(upFile.FileName))  
    13.                 srcFiles.Insert();  
    14.         }  
    15.     }  
    16.     bool CheckFileType(string fileName)  
    17.     {  
    18.         return Path.GetExtension(fileName).ToLower() == ".doc";  
    19.     }  
    20. </script>  
    21.   
    22. <html xmlns="http://www.w3.org/1999/xhtml">  
    23. <head runat="server">  
    24.     <title>无标题页</title>  
    25. </head>  
    26. <body>  
    27.     <form id="form1" runat="server">  
    28.     <div>  
    29.         <asp:Label ID="lblFile" runat="server" AssociatedControlID="upFile" Text="Word Document"></asp:Label>  
    30.         <asp:FileUpload ID="upFile" runat="server" />  
    31.         <asp:Button ID="btnAdd" runat="server" Text="Add Document" OnClick="btnAdd_Click" /><hr />  
    32.           
    33.         <asp:Repeater ID="rptFiles" DataSourceID="srcFiles" runat="server">  
    34.         <ItemTemplate><li>  
    35.         <asp:HyperLink ID="lnkFile" Text='<%Eval("FileName")%>' NavigateUrl='<%Eval("Id","~/FileHandler.ashx?id={0}") %>' runat="server" /></li>  
    36.         </ItemTemplate>  
    37.         </asp:Repeater>  
    38.           
    39.         <asp:SqlDataSource ID="srcFiles" runat="server"  
    40.             ConnectionString="Server=./SQLExpress;Integrated Security=True;  
    41.             AttachDbFilename=|DataDirectory|FilesDB.mdf;User Instance=True"  
    42.             SelectCommand="select Id,FileName from Files"  
    43.             InsertCommand="insert Files(FileName,FileBytes) values (@FileName,@FileBytes)" >  
    44.             <InsertParameters>  
    45.                <asp:ControlParameter Name="FileName" ControlID="upFile" PropertyName="FileName" />  
    46.                <asp:ControlParameter Name="FileBytes" ControlID="upFile" PropertyName="FileBytes" />  
    47.             </InsertParameters>  
    48.         </asp:SqlDataSource>  
    49.         <!--InsertParameters从与SqlDataSource控件相关联的对象获取包含InsertCommand属性所使用的参数的参数集合。-->  
    50.         <!--ControlParameter对象用于将参数设置为ASP.NET网页中的控件的属性值。  
    51.             使用ControlID属性指定控件。使用PropertyName属性指定提供参数值的属性的名称。-->  
    52.         <!--FileBytes以字节数组形式获取上传文件内容。-->  
    53.     </div>  
    54.     </form>  
    55. </body>  
    56. </html>  

    效果:

    页 面显示了当前在数据库中Word文档的列表。可以点击其中的文件查看文件内容。点击文档名会链接到FileHandler.ashx页面,这个文件是一个 普通的HTTP处理程序文件。当有人用特定的路径请求文件时,HTTP处理程序用于执行代码。下面是FileHandler.ashx文件的代码。
    [c-sharp] view plaincopy
    1. <%@ WebHandler Language="C#" Class="FileHandler" %>  
    2. using System;  
    3. using System.Web;  
    4. using System.Data;  
    5. using System.Data.SqlClient;  
    6. public class FileHandler : IHttpHandler {  
    7.     const string conString = @"Server=./SQLExpress;Integrated Security=True;  
    8.         AttachDbFileName=|DataDirectory|FilesDB.mdf;User Instance=True";   
    9.     public void ProcessRequest (HttpContext context) {  
    10.         context.Response.ContentType = "application/msword";        
    11.         SqlConnection con = new SqlConnection(conString);  
    12.         SqlCommand cmd = new SqlCommand("SELECT FileBytes FROM Files WHERE Id=@Id", con);  
    13.         cmd.Parameters.AddWithValue("@Id", context.Request["Id"]);  
    14.         using (con)  
    15.         {  
    16.             con.Open();  
    17.             byte[] file = (byte[])cmd.ExecuteScalar();  
    18.             context.Response.BinaryWrite(file);  
    19.         }  
    20.     }  
    21.     public bool IsReusable {  
    22.         get {  
    23.             return false;  
    24.         }  
    25.     }  
    26.   
    27. }  
    当请求FileHandler.ashx页面时,执行了ProcessRequest()方法。该方法取得名为Id的查询字符串项,并从数据库表 Files中获取匹配的记录。数据库记录包含Word文档内容字节数组。再用Response.BinaryWrite()方法把字节数组发送到浏览器。
    关于HTTP处理程序,现在还没学,上面的FileHandler.ashx页面的代码大部分都不太理解,等以后学到之方面的内容了,再回来解析一下吧。

3.  上传大文件

  • 上传大文件时,需要做一些额外工作。你可能不希望把服务器端的所有内存都消耗在容纳整个文件上。处理大文件时,需要使用多个可托管(manageable)内存块来处理文件。
    首 先,为了处理大文件需要配置应用程序。有两个配置项影响着向服务器提交大文件:httpRuntime maxRequestLength和httpRuntime requestLengthDiskThreshold。maxRequestLength指定提交的表单能被服务器端接收的最大值。默认不能提交大于 4MB的表单,否则会得到一个异常。如果要上传超过4MB的文件就需要更改该配置。requestLengthDiskThreshold决定如何把上表 单缓存在文件系统。asp.net framework可以把大的文件缓存在文件系统中,当文件大小超过requestLengthDiskThreshold设置后,文件的余下部分被缓存 在文件系统(asp.net临时文件夹中)。默认情况下,把超过80KB的提交数据缓存到文件缓存器中,可以修改 requestLengthDiskThreshold来设置新的阈值(requestLengthDiskThreshold设置的值必须小于 maxRequestLength设置值)。下面代码的Web配置文件设置为可以上传不超过10MB的文件,并把缓存阈值改为100kB。
    <configuration>
      <system.web>
        <httpRuntime maxRequestLength="10240" requestLengthDiskThreshold="100"/>
      </system.web>
    </configuration>
    下面代码演示如何高效地把一个大文件存储到数据库表中。
    [c-sharp] view plaincopy
    1. <%@ Page Language="C#" %>  
    2. <%@ Import Namespace="System.IO" %>  
    3. <%@ Import Namespace="System.Data" %>  
    4. <%@ Import Namespace="System.Data.SqlClient" %>  
    5. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
    6. <script runat="server">  
    7.     const string conString = @"Server=./SQLExpress;Integrated Security=True;AttachDbFilename=|DataDirectory|FilesDB.mdf;User Instance=True";  
    8.     //@在c#中表示后面的字符串强制不转义,在里面的转义字符无效  
    9.     void btnAdd_Click(object sender, EventArgs e)  
    10.     {  
    11.         if (upFile.HasFile)  
    12.         {  
    13.             if (CheckFileType(upFile.FileName))  
    14.             {  
    15.                 AddFile(upFile.FileName, upFile.FileContent);  
    16.                 //FileUpload.FileContent以流(stream)形式获取上传文件内容。  
    17.                 rptFiles.DataBind();  
    18.             }  
    19.         }  
    20.     }  
    21.     bool CheckFileType(string fileName)  
    22.     {  
    23.         return Path.GetExtension(fileName).ToLower() == ".doc";  
    24.     }  
    25.     //Stream类是所有流的抽象基类,提供字节序列的一般视图。  
    26.     void AddFile(string fileName, Stream upload)  
    27.     {  
    28.         SqlConnection con = new SqlConnection(conString);  
    29.         SqlCommand cmd = new SqlCommand("INSERT Files (FileName) Values (@FileName);" + "SELECT @Identity=SCOPE_IDENTITY()", con);  
    30.         //SELECT @Identity=SCOPE_IDENTITY()声明一个参数,在后面传入一个值,可以避免SQL注入,比直接拼SQL语句好  
    31.         //获取添加记录的自增ID。  
    32.         cmd.Parameters.AddWithValue("@FileName", fileName);  
    33.         //SqlCommand.Parameters用于获取SqlParameterCollection。  
    34.         //SqlParameterCollection表示与 SqlCommand 相关联的参数的集合以及各个参数到 DataSet 中列的映射。  
    35.         //AddWithValue将一个值添加到 SqlParameterCollection 的末尾。  
    36.         SqlParameter idParm = cmd.Parameters.Add("@Identity", SqlDbType.Int);  
    37.         idParm.Direction = ParameterDirection.Output;  
    38.   
    39.         using (con)  
    40.         {  
    41.             con.Open();  
    42.             cmd.ExecuteNonQuery();  
    43.             int newFileId = (int)idParm.Value;  
    44.             StoreFile(newFileId, upload, con);  
    45.         }  
    46.         //在using作用域之后自动释放对象(调用Dispose方法),相当于con.close()。  
    47.     }  
    48.       
    49.     void StoreFile(int fileId, Stream upload, SqlConnection connection)  
    50.     {  
    51.         //从流br内读取长度为8040的数据  
    52.         int bufferLen = 8040;  
    53.         BinaryReader br = new BinaryReader(upload);  
    54.         byte[] chunk = br.ReadBytes(bufferLen);  
    55.           
    56.         //修改数据表Files内Id为fileId的数据流为chunk  
    57.         SqlCommand cmd = new SqlCommand("UPDATE Files SET FileBytes=@Buffer WHERE Id=@FileId", connection);  
    58.         cmd.Parameters.AddWithValue("@FileId", fileId);  
    59.         cmd.Parameters.Add("@Buffer", SqlDbType.VarBinary, bufferLen).Value = chunk;  
    60.         cmd.ExecuteNonQuery();  
    61.   
    62.         //###AAA###追加数据表Files内Id为fileId的数据流  
    63.         SqlCommand cmdAppend = new SqlCommand("UPDATE Files SET FileBytes .WRITE(@Buffer, NULL, 0) WHERE Id=@FileId", connection);  
    64.         cmdAppend.Parameters.AddWithValue("@FileId", fileId);  
    65.         cmdAppend.Parameters.Add("@Buffer", SqlDbType.VarBinary, bufferLen);  
    66.         chunk = br.ReadBytes(bufferLen);  
    67.   
    68.         //当br流中有可读数据时,追加至###AAA###  
    69.         while (chunk.Length > 0)  
    70.         {  
    71.             cmdAppend.Parameters["@Buffer"].Value = chunk;  
    72.             cmdAppend.ExecuteNonQuery();  
    73.             chunk = br.ReadBytes(bufferLen);  
    74.         }  
    75.         br.Close(); //关闭流  
    76.     }  
    77. </script>  
    78.   
    79. <html xmlns="http://www.w3.org/1999/xhtml">  
    80. <head runat="server">  
    81.     <title>无标题页</title>  
    82. </head>  
    83. <body>  
    84.     <form id="form1" runat="server">  
    85.     <div>  
    86.     <asp:Label ID="lblFile" runat="server" AssociatedControlID="upFile" Text="Word Document"></asp:Label>  
    87.         <asp:FileUpload ID="upFile" runat="server" />  
    88.         <asp:Button ID="btnAdd" runat="server" Text="Add Document" OnClick="btnAdd_Click" /><hr />  
    89.           
    90.         <asp:Repeater ID="rptFiles" DataSourceID="srcFiles" runat="server">  
    91.         <ItemTemplate>  
    92.         <li>  
    93.         <asp:HyperLink ID="lnkFile" Text='<%#Eval("FileName")%>' NavigateUrl='<%#Eval("Id","~/FileHandlerLarge.ashx?id={0}") %>' runat="server" />  
    94.         </li>  
    95.         </ItemTemplate>  
    96.         </asp:Repeater>  
    97.           
    98.         <asp:SqlDataSource ID="srcFiles" runat="server"  
    99.             ConnectionString="Server=./SQLExpress;Integrated Security=True;  
    100.             AttachDbFilename=|DataDirectory|FilesDB.mdf;User Instance=True"  
    101.             SelectCommand="select Id,FileName from Files" >  
    102.         </asp:SqlDataSource>  
    103.     </div>  
    104.     </form>  
    105. </body>  
    106. </html>  
    在上面代码中,首先调用了AddFile()方法,该方法在包含文件名字段的数据库表Files中新增一行。然后调用StoreFile()方法,该方法 把上传文件的实际字节添加到数据库中。上传文件被分成8040字节大小的块。注意在更新数据库字段FileBytes时,SQL UPDATE语句包含.WRITE字句。该代码中的页面不会在内存中装整个上传文件,上传文件以8040字节大小的块从文件系统中取出,产一块一块存入 SQL Server中。
    点击文件名将执行FileHandle.aspx HTTP处理程序,该项处理程序从数据库中获取先中的文件并把它发送到浏览器。下面代码包含了这个处理程序。
    [c-sharp] view plaincopy
    1. <%@ WebHandler Language="C#" Class="FileHandlerLarge" %>  
    2. using System;  
    3. using System.Web;  
    4. using System.Data;  
    5. using System.Data.SqlClient;  
    6. public class FileHandlerLarge : IHttpHandler {  
    7.     const string conString = @"Server=./SQLExpress;Integrated Security=True;  
    8.         AttachDbFileName=|DataDirectory|FilesDB.mdf;User Instance=True";  
    9.     public void ProcessRequest (HttpContext context) {  
    10.         context.Response.Buffer = false;  
    11.         context.Response.ContentType = "application/msword";  
    12.         SqlConnection con = new SqlConnection(conString);  
    13.         SqlCommand cmd = new SqlCommand("SELECT FileBytes FROM Files WHERE Id=@Id", con);  
    14.         cmd.Parameters.AddWithValue("@Id", context.Request["Id"]);  
    15.         using (con)  
    16.         {  
    17.             con.Open();  
    18.             SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);  
    19.             if (reader.Read())  
    20.             {  
    21.                 int bufferSize = 8040;  
    22.                 byte[] chunk = new byte[bufferSize];  
    23.                 long retCount;  
    24.                 long startIndex = 0;  
    25.   
    26.                 retCount = reader.GetBytes(0, startIndex, chunk, 0, bufferSize);  
    27.   
    28.                   
    29.                 while (retCount == bufferSize)  
    30.                 {  
    31.                     context.Response.BinaryWrite(chunk);  
    32.   
    33.                     startIndex += bufferSize;  
    34.                     retCount = reader.GetBytes(0, startIndex, chunk, 0, bufferSize);  
    35.                 }  
    36.   
    37.                 byte[] actualChunk = new Byte[retCount - 1];  
    38.                 Buffer.BlockCopy(chunk, 0, actualChunk, 0, (int)retCount - 1);  
    39.                 context.Response.BinaryWrite(actualChunk);  
    40.                                  
    41.             }  
    42.         }  
    43.     }  
    44.    
    45.     public bool IsReusable {  
    46.         get {  
    47.             return false;  
    48.         }  
    49.     }  
    50.   
    51. }  
    上面代码中的HTTP处理程序使用SqlDataReader从数据库中获取文件。注意,SqlDataReader使用 CommandBehavior.SequentialAccess参数获取数据。这个参数使SqlDataReader以流的方式加载数据。数据库字段 的内容以8040字节大小的块取入内存中,这些内容块用Response.BinaryWrite()方法写入浏览器。另外注意这个处理程序禁止用了响应 缓存,Response.Buffer属性的值被设成False。由于禁用了缓存,处理程序输出就不会在传输到浏览器前缓在服务器端的内存中。
posted @ 2013-03-10 10:12  天涯海角路  阅读(265)  评论(0)    收藏  举报