zoukankan      html  css  js  c++  java
  • HTTP文件上传

    看到网上很多链接文件(word、pdf...)可以下载,想制作http下载链接。

    其实是将某文件直接放在服务器上搭建的网站上某目录下即可,例如:http://xxx:port/UpgradePack/525.jpg 或者  http://xxx:port//博客.pdf。

    http服务器有很多种, 如tomcat,apache,IIS等,也可以直接下载http服务器hfs(http file server)快速搭建。

    一、利用C#模拟文件上传至服务器

    主要有以下三种基本方法:

    方法一:用Web控件FileUpload

    上传到网站根目录,适用于asp.net webForm

     <form id="form1" runat="server">
            <%--上传文件大小有限制--%>
            <asp:FileUpload ID="FileUpload1" AllowMultiple="true" runat="server" />
            <br />
            <br />
            <%--直接进FileUploadTest.aspx.cs中处理--%>
            <asp:Button ID="Button1" runat="server" Text="上传到服务器" OnClick="Button1_Click" />
            <asp:Label ID="Label1" runat="server" Text="" Style="color: Red"></asp:Label>
        </form>
    
    
     protected void Button1_Click(object sender, EventArgs e)
            {
                //处理单个文件
                //if(FileUpload1.HasFile)
                //{
                //    FileUpload1.SaveAs(Server.MapPath("~/Files/") + FileUpload1.FileName);
                //    Label1.Text = "上传成功";
                //}
                //else
                //{
                //    Label1.Text = "上传失败";
                //}
    
                if (FileUpload1.HasFile)
                {
                    foreach (var item in FileUpload1.PostedFiles)
                    {
                        FileUpload1.SaveAs(Server.MapPath("~/Files/") + item.FileName);
                    }
                    Label1.Text = "上传成功";
                }
                else
                {
                    Label1.Text = "上传失败";
                }
            }
    View Code

    允许一次选择多个文件:AllowMultiple="true"

    注意:FileUpLoad上传控件,限制文件上传大小默认4096kb(4MB)

    如果我们要上传超过此大小的文件,会出现错误界面等……

    如果想增大允许上传的文件大小,则需要修改web.config文件代码:

    <configuration>
        <system.web>
            <httpRuntime maxRequestLength="4096" executionTimeout="120"/>
        </system.web>
    </configuration>

    说明:

             maxRequestLength属性限制文件上传的大小,是以KB为单位的,默认值为4096KB,而最大上限为2097151KB,大约是2GB。

             executionTimeout属性限制文件上传的时间,以秒(s)为单位,默认值为90 s,如果您考虑到所设计的Web应用系统上传时间要超过90 s可延长设定值。

    方法二:用Html控件HtmlInputFile

         <form id="form1" runat="server">
         <input type="file" id="file1" runat="server" />
         <asp:Button ID="Button1" runat="server" Text="上传" OnClick="Button1_Click" />
         <asp:Label ID="Label1" runat="server" Text="" Style="color: Red"></asp:Label>
         </form>
    
         protected void Button1_Click(object sender, EventArgs e)
         {
             if (file1.PostedFile.ContentLength > 0)
             {
                  file1.PostedFile.SaveAs(Server.MapPath("~/") + Path.GetFileName(file1.PostedFile.FileName));
                  Label1.Text = "上传成功!";
             }
         }
    View Code

    选择多个文件:multiple="multiple"  ,但是发现后端没有获取文件列表的方法/属性。不知道是不是这个HtmlInputFile只能单文件上传,有哪位清楚,还望告知下。

    注意两个区别:

    一:FileUpload.FileName获取客户端上传文件名(不带路径),而file1.PostedFile.FileName 和Request.Files["file"].FileName在不同浏览器下情况不同:IE8下获得的是客户端上传文件的完全限定名(带路径),谷歌、苹果等浏览器下则仍为文件名(不带路径)。

    二:FileUpload控件有HasFile属性,用于判断用户是否选择了上传文件,而后面两种方法则需要通过判断上传文件大小ContentLength属性,当用户没有选择上传文件时,该属性值为0。

    可以看出FileUpload封装程度更高,但灵活性也稍差。

    方法三:Html元素input type="file"

    • 通过表单提交,获取Request.Files
     <%-- enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。[在使用包含文件上传控件的表单时,必须使用multipart/form-data。]--%>
        <form id="form1" runat="server"   enctype="multipart/form-data">
           <input type="file" name="file" multiple="multiple" />
            <br />
            <br />
            <input type="text" name="author" value="huy" />
         <asp:Button ID="Button1" runat="server" Text="上传到服务器" OnClick="Button1_Click" />
         <asp:Label ID="Label1" runat="server" Text="" Style="color: Red"></asp:Label>
        </form>
    
    
     protected void Button1_Click(object sender, EventArgs e)
            {
                string name = Request.Form["author"];
                Response.Write(name);
                HttpFileCollection files = Request.Files;
                if (files.Count > 0)
                {
                    for (int i = 0; i < files.Count; i++)
                    {
                        files[i].SaveAs(Server.MapPath("~/Files/") + Path.GetFileName(files[i].FileName));
                    }
                    Label1.Text = "上传成功";
                }
                else
                {
                    Label1.Text = "上传失败";
                }
            }
    View Code

    注意:form需要设置,enctype="multipart/form-data"。。多文件上传(multiple="multiple")  HTML5中支持

    官网参考:HttpRequest.Files

    • 也可以利用Ajax提交,FormData(),上传的文件支持移除,
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="InputFileAjax.aspx.cs" Inherits="WebFormTest.FileUpload.InputFileAjax" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <style>
            /*为了不显示控件的 未选择任何文件/上传个数*/
            .surfaceThree {
                position: relative;
                width: 80px;
                background: gainsboro;
                border-radius: 6px;
                text-align: center;
                line-height: 30px;
                font-size: 16px;
                color: black;
            }
    
                .surfaceThree input {
                    position: absolute;
                    top: 5px;
                    right: -110px;
                    height: 30px;
                    /* 重点代码让input隐藏 */
                    opacity: 0;
                }
        </style>
    
        <script src="../Scripts/jquery-1.10.2.min.js"></script>
    </head>
    <body>
        <form id="form1" runat="server">
            <div id="email" runat="server">
            </div>
    
            <div class="surfaceThree">
                选择文件
       <input type="file" multiple="multiple" name="fileUpload" id="fileUpload" onchange="uploadLogic(this)" />
            </div>
            <br />
            <br />
            <input type="text" name="author" value="huy" />
    
    
    
            <asp:Button ID="Button1" runat="server" Text="上传到服务器" OnClick="Button1_Click" OnClientClick="return addFiles()" />
            <asp:Label ID="Label1" runat="server" Text="" Style="color: Red"></asp:Label>
        </form>
    
        <script type="text/javascript">
    
            //单击上传的时候 增加手动选择的附件
            function addFiles() {
                var formData = new FormData();
                for (var i = 0; i < fileLists.length; i++) {
                    formData.append('file', fileLists[i]);  //file可以任意
                }
    
                $.ajax({
                    url: "InputFileAjax.ashx",
                    data: formData,
                    type: "post",
                    async: false,
                    contentType: false,
                    processData: false,
                    success: function (msg) {
                        var rs = jQuery.parseJSON(data);
                        if (rs.ReturnCode == 1) {
                            console.log("手動添加附件成功");
                        } else if (rs.ReturnCode == 0) {
                            console.log(rs.Message);
                        }
                        else {
                            alert("手動添加附件失敗:" + rs.Message);
                        }
                    },
                    error: function (e) {
                        alert("手動添加附件失敗");
                    }
                });
            }
    
            fileLists = [];
            //多文件上传逻辑
            function uploadLogic(obj) {
                var filrarr = obj.files;
                //console.log("这次上传的文件:");
                //console.log(filrarr);
                if ((fileLists.length + filrarr.length) > 10) {
                    alert("手動添加附件不鞥超過10個!");
                    return;
                }
                files = Array.prototype.slice.call(filrarr); //需要能动态修改fileList即可,第一想法是将它转化为数组进行操作。
                fileLists = fileLists.concat(files);
                console.log("现在总的文件:");
                console.log(fileLists);
    
                var email = $('#email');
                for (var i = 0; i < filrarr.length; i++) {
    
                    var addtr = $("<div style='margin: 5px 10px;display:inline-block'>" +
                        "<div class='label label-primary' title='" + filrarr[i].name + "' style='vertical-align: middle;margin-right: 10px;display:inline-block;150px;overflow: hidden; text-overflow: ellipsis;height:20px'>" +
                        filrarr[i].name + "</div>" +
                        "<input type="button" id='btnRemoveAttach' style='color: red;border-radius: 6px' onclick='RemoveMulFileUpload(this,"" + filrarr[i].name + "")' value="移除" />" +
                        "</div>");
                    email.append(addtr);
                }
            }
    
            //移除多文件上传控件的文件
            function RemoveMulFileUpload(div, filename) {
                var ind = $(div).parent().index();
                fileLists.splice(ind, 1);//修改fileLists
                $(div).parent().remove();
                console.log("删除文件:" + filename + "。后现在总的文件:");
                console.log(fileLists);
            }
    
    
        </script>
    </body>
    </html>
    View Code

    注意:

    1、processData参数:

    用于对data参数进行序列化处理,默认值是true。默认情况下发送的数据将被转换为对象,对于文件File则不需要转换,此参数需要设置为false。否则可能报非法调用(Illegal invocation)。

    2、普通参数传递与获取:

    formData.append("param1","参数1");     

    string p1=Request.Form["param1"];  //普通参数获取

    后端 一般处理页

    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Web;
    
    namespace WebFormTest.FileUpload
    {
        /// <summary>
        /// InputFileAjax1 的摘要说明
        /// </summary>
        public class InputFileAjax1 : IHttpHandler
        {
    
            public void ProcessRequest(HttpContext context)
            {
                context.Response.ContentType = "text/plain";
                //context.Response.Write("Hello World");
                AddUploadFiles(context);
    
            }
    
            /// <summary>
            /// 增加手动上传的文件
            /// </summary>
            /// <param name="context"></param>
            private void AddUploadFiles(HttpContext context)
            {
                var result = new Result() { ReturnCode = 0 };
                try
                {
                    if (context.Request.Files.Count <= 0)
                    {
                        result.Message = "沒有額外添加附件";
                        context.Response.Write(JsonConvert.SerializeObject(result));
                    }
                    if (context.Request.Files.Count > 10)
                    {
                        result.Message = "手動添加附件不鞥超過10個";
                        context.Response.Write(JsonConvert.SerializeObject(result));
                    }
                    HttpFileCollection files = context.Request.Files;
                    if (files.Count > 0)
                    {
                        for (int i = 0; i < files.Count; i++)
                        {
                            files[i].SaveAs(context.Server.MapPath("~/Files/") + Path.GetFileName(files[i].FileName));
                        }
                    }
                    context.Response.Write(JsonConvert.SerializeObject(result));
                }
                catch (Exception ex)
                {
                    result.Message = ex.ToString();
                    context.Response.Write(JsonConvert.SerializeObject(result));
                }
            }
    
    
            public bool IsReusable
            {
                get
                {
                    return false;
                }
            }
        }
    
        public class Result
        {
            /// <summary>
            /// 1成功,0错误
            /// </summary>
            public int ReturnCode { get; set; }
            public string Message { get; set; }
        }
    }
    View Code

    其中:未选择任何文件/上传个数不显示

    常规的是这样,

    选择文件后,这个“未选择任何文件”则显示成 选择了几个文件。但是移除文件 这个个数不会变。所以想办法不需要显示这个。

          .surfaceThree {
        position: relative;
        /*height: 30px;*/
         80px;
        background: gainsboro;
        border-radius: 6px;
        text-align: center;
        line-height: 30px;
        font-size:16px;
        color: black;
    }
    
    .surfaceThree input {
        position: absolute;
        top: 5px;
        right: -110px;
         /*color: #fff;*/ 
        height: 30px;
        /* 重点代码让input隐藏 */
        opacity: 0;
    }
    
    
    <div class="surfaceThree">选择文件
       <input type="file"  multiple="multiple" name="fileUpload" id="fileUpload"  onchange="uploadLogic(this)" />
     </div>
    View Code

     

    上传图片限制大小、类型、像素

    用到input标签来上传图片。图片有很多格式我们只需要其中的几种,就需要对用户上传的文件进行验证,在HTML5中有一个新的属性:accept文件类型限制。但是通常我们会用javascript或jQuery编写方法进行验证图片的大小限制、类型判断、像素判断。

    function handleChange(file) {
        var fileTypes = [".jpg", ".png"];  //我们所需要的图片格式
        var filePath = file.value;
        if (filePath) {
            var filePic = file.files[0];            //选择的文件内容--图片
            var fileType = filePath.slice(filePath.indexOf("."));   //选择文件的格式
            var fileSize = file.files[0].size;            //选择文件的大
            if (fileTypes.indexOf(fileType) == -1) {  //判断文件格式是否符合要求
                alert("文件格式不符合要求!");
                return
            
            if (fileSize > 1024 * 1024) {
                alert("文件大小不能超过1M!");
                return
            
            var reader = new FileReader();
            reader.readAsDataURL(filePic);
            reader.onload = function (e) {
                var data = e.target.result;
                //加载图片获取图片真实宽度和高度
                var image = new Image();
                image.onload = function () {
                    var width = image.width;
                    var height = image.height;
                    if (width == 720 | height == 1280) {  //判断文件像素
                        //上传图片
                    } else {
                        alert("图片尺寸应为:720*1280!");
                        return;
                    }
                };
                image.src = data;
            };
        } else {
            return
        }
    }
    View Code

    表单提交

    前端控件都应该有一个name属性和”当前值“,在提交时,它们将以 name=value 的形式做为提交数据的一部分。

    前台form表单的提交方式有很多种,例如:

    1、form表单submit直接提交的方法
    2、Ajax提交的方法
    j3、query提交的方法
    这里总结一下ajax提交的两种方式:

    1.serialize() 方法:
    通过序列化表单值,创建 URL 编码文本字符串。我们可以选择一个或多个表单元素(比如 input 及/或 文本框),或者 form 元素本身。序列化的值可在生成 AJAX 请求时用于 URL 查询字符串中。
    所用到的语法为:$("form").serialize()

    提交方法的代码段:$('form').submit(function() {

    alert($(this).serialize());
    return false;
    });

    最终序列化后,表单中数据会以下面这种方式提交到后台:a=1&b=2&c=3&d=4&e=5
    这种方式处理表单时所适用的input标签类型是有限的,只适用于一些常用的类型例如text、checkbox、select、date等等,但是对于file文件类型的input框并不适用,那我们在用到ajax提交方式的时候应该如何提交file类型的input框数据呢?

    2.封装FormData 对象,直接用$.ajax提交
    将form表单中的内容封装成formdata的数据格式
    FormData 对象可以把form中所有表单元素的name与value组成一个queryString,提交到后台,在使用Ajax提交时,使用FormData对象可以减少拼接queryString的工作量。

    FormData的使用方法也是非常简单,直接传入form表单对象即可,如下:

    var form = $('#form1');
    var formdata = new FormData(form);
    使用这种方式将数据封装后,file类型的文件数据即可以键值对的方式封装在formdata中,然后用ajx提交,方法如下:

    $.ajax({  
            type : "POST",  
            url : "houtai/123.do",  
            data : formData,
            async: false,  
            cache: false,  
            contentType: false,  
            processData: false,
            success : function(msg) {  
                if(msg){
                alert('提交成功!');
                } 
            }  
    });  
    View Code

    需要注意的是:以formdata的方式提交时需要添加async: false, 同步,否则后台无法接收到前台传过来的file文件数据,这样的提交方式,既可以提交任何一种type类型标签,又可以在提交之后得到返回结果,方便快捷又实用。

    form表单提交过程

    二、IIS搭建HTTP文件服务器(文件上传下载)

    IIS环境准备

    1、  安装IIS

    打开“控制面板”,找到“程序与功能”, 找到“启用或关闭Windows功能”,点进去之后,将“Internet Information Services”下所有节点都打勾(这样就搭建了一个功能完全的HTTP/FTP服务器),注意“WebDAV发布”必须要安装,这个跟文件服务器中文件访问权限有着很大的关系,如果想对服务器中某个具有读写权限的文件夹进行读写,就必须开启该选项,如下图所示:

    2、  添加网站

    添加自己的一个网站,鼠标移到“网站”上方,右键点击鼠标,弹出菜单,在菜单中点击“添加网站”,如下图所示:

    根据如下图所说的步骤,填写网站名称及选择物理路径,其他默认即可,然后点击“确定”按钮:

     

    本网站仅作为文件服务器,因此,将服务器的文件浏览功能打开,以便浏览,具体操作为鼠标双击“目录浏览”后,将“操作”一栏里的“启用”打开,如下图所示:

    3、WebDAV创作规则

    进入,点击“WebDAV设置”,将①②所示红色框内的属性设置为图中所示的属性,并点击“应用”,如下图所示:

    返回到“WebDAV创作规则”,点击“添加创作规则”,如下图所示:

    在弹出的“添加创作规则”,将“允许访问此内容”选中,权限“读取、源、写入”都打勾,点击“确定”按钮关闭,如下图所示:

     

    返回到“WebDAV创作规则”,点击“启用WebDAV”,

    双击“身份验证”,将“匿名身份验证”(客户端读取文件)及“Windows身份验证”(客户端写入、删除)启用,如下所示:

     

    为了能让文件服务器具有写入、删除功能,可以在现有Windows系统账户上新建一个隶属于“Power Users”的账户“test”(密码:123),如下图所示:

     

    以上关于如何创建账户的内容,请自行百度

    为了能让test账户顺利访问存放于E盘下的“TestWebSite”文件夹,需要为该文件夹设置Power Users组的访问权限,如下图所示:

    关于如何将特定组或用户设置权限的问题,请自行百度。

    查看本机IIS的IP地址,并在浏览器输入该IP,将会显示网站下内容。

    自此,IIS文件服务器的搭建已经完毕。

    使用C# WebClient访问IIS文件服务器 

    在使用WebClient类之前,必须先引用System.Net命名空间,文件下载、上传与删除的都是使用异步编程,也可以使用同步编程,

    这里以异步编程为例:

    1)  文件下载:

    //下载文件
                string fileHttpPath = @"http://localhost/js/javascript/01.js";
                string saveName = @"E:IIS_DeployFileSystem1.js";
                SY.Filer.Http.HttpDownloadFile.DownloadFileAsync(fileHttpPath,saveName);
                Console.WriteLine("文件下载结束");
    
    /// <summary>
        /// http文件下载
        /// </summary>
        public class HttpDownloadFile
        {
            /// <summary>
            /// 异步文件下载
            /// </summary>
            /// <param name="fileHttpPath">文件的http路径</param>
            /// <param name="saveLocalName">本地保存的文件名称</param>
            public static void DownloadFileAsync(string fileHttpPath, string saveLocalName)
            {
                try
                {
                    using (WebClient client = new WebClient())
                    {
                        //使用默认的凭据——读取的时候,只需默认凭据就可以
                        client.Credentials = CredentialCache.DefaultCredentials;
                        Uri uri = new Uri(fileHttpPath);
    
                        client.DownloadProgressChanged += Client_DownloadProgressChanged;
                        client.DownloadFileCompleted += Client_DownloadFileCompleted;
                        //异步下载指定路径
                        client.DownloadFileAsync(uri, saveLocalName);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
    
            //下载完成事件处理程序
            private static void Client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
            {
                if (e.Cancelled)
                {
                    Console.WriteLine("文件下载被取消");
                }
                //获取一个值,该值指示异步操作期间发生的错误 
                if (e.Error == null)
                {
                    Console.WriteLine("文件下载成功");
                }
                else
                {
                    //throw e.Error; //【异步操作 上层捕获不到】
                    Console.WriteLine(e.Error.ToString());
                }
            }
    
            //下载进度事件处理程序
            private static void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
            {
                Console.WriteLine($"{e.ProgressPercentage}:{e.BytesReceived}/{e.TotalBytesToReceive}");
            }
    } 
    View Code

    2)  文件上传:

     //下载上传
                string fileHttpPath = @"http://localhost/txt/Readme.txt";
                string localfile = @"D:、入职20180820Readme.txt";
                SY.Filer.Http.HttpUploadFile.UploadFileAsync(fileHttpPath, localfile);
                Console.WriteLine("文件上传结束");
    
    
    /// <summary>
        /// http文件上传
        /// </summary>
        public class HttpUploadFile
        {
            /// <summary>
            /// 异步文件上传
            /// </summary>
            /// <param name="fileSaveHttpPath">文件的http路径</param>
            /// <param name="saveLocalName">本地的文件名称</param>
            public static void UploadFileAsync(string fileSaveHttpPath, string localFile)
            {
                try
                {
                    using (WebClient client = new WebClient())
                    {
                        //client.Credentials = CredentialCache.DefaultCredentials;
    
                        //使用Windows登录方式
                        client.Credentials = new NetworkCredential("test", "hy123456@");
                        Uri _uri = new Uri(fileSaveHttpPath);
    
                        //注册上传进度事件通知
                        client.UploadProgressChanged += Client_UploadProgressChanged;
                        client.UploadFileCompleted += Client_UploadFileCompleted;
    
                        //异步 将选择的上传文件到服务器
                        client.UploadFileAsync(_uri, "PUT", localFile);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
    
            //上传完成事件处理程序
            private static void Client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
            {
                if (e.Cancelled)
                {
                    Console.WriteLine("文件上传被取消");
                    return;
                }
                //获取一个值,该值指示异步操作期间发生的错误 
                if (e.Error == null)
                {
                    Console.WriteLine("文件上传成功");
                }
                else
                {
                    //throw e.Error; //【异步操作 上层捕获不到】
                    Console.WriteLine(e.Error.ToString());
                }
            }
            //上传进度事件处理程序
            private static void Client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
            {
                Console.WriteLine($"{e.ProgressPercentage}:{e.BytesSent}/{e.TotalBytesToSend}");
            }
    
    
        }
    View Code

    三、异常及解决方案

    1、上传文件报错:远程服务器返回错误: (409) 冲突

      由于服务器上不存在上传文件设定的目录,而webclient不会自动创建文件夹所导致。手工创建对应的文件夹即可。

    2、上传文件报错:远程服务器返回错误: (403) 已禁止

       服务器上文件夹未设置用户组某用户的访问权限

     

  • 相关阅读:
    Ubuntu1404: 将VIM打造为一个实用的PythonIDE
    事前备份胜于事后恢复
    做事不应当拘泥于既定的循例
    简单生活
    《犹太人思考术》读后感
    产品开发与运维的中心准则
    Awk使用一例:获取ASCII可见字符
    使用Sed和Awk实现批量文件的文本替换
    编写更少bug的程序的六条准则
    【JS新手教程】JS中的split()方法,拆分字符串
  • 原文地址:https://www.cnblogs.com/peterYong/p/10871997.html
Copyright © 2011-2022 走看看