文件上传的几个 - 示例

Posted 神牛003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件上传的几个 - 示例相关的知识,希望对你有一定的参考价值。

本篇将要和朋友们分享的是几个上传文件的例子和逻辑步奏及自定义个简单的js上传插件我取名为shenniu.upfile-0.0.1.js;近来在讨论组中很有几个朋友咨询上传文件的代码和怎么下载上传的文件,所以写了此篇文章,希望能为朋友们解答一些疑惑或能带来帮助,也谢谢各位多多支持点赞。

 

以上是个人的看法,下面来正式分享今天的文章吧:

. 使用iis发布保存上传文件的文件夹

. 示例A - 普通表单上传文件,Request.Files获取上传文件

. 示例B - 普通表单上传文件,HttpPostedFileBase获取上传文件

. 示例C - ajax+FormData上传文件,Request.Files获取上传文件

. 示例D - 自定义上传插件,Request.Files获取上传文件并提交表单内容

 

下面一步一个脚印的来分享:

. 使用iis发布保存上传文件的文件夹

首先,因为我们上传文件后,需要查看或者下载这个文件,通常分为两种形式;一种把上传的文件上传到程序的根目录中的某个文件夹中,这种就可以直接通过站点的虚拟路径来访问,这种其实也是使用了iis发布的;第二种是通过程序上传到服务器的某个磁盘中,这种路径通常就不在上传程序站点的目录下,因为想让用户通过其他的url地址访问下载文件,iis发布只是其中一种;其实用iss发布保存上传文件的文件夹和发布程序一样差不多;

我们随便找个某磁盘下面的文件夹当做保存上传文件的文件夹,我这里磁盘路径是:D:\\D\\TTest这个TTest文件夹,然后放几张测试的图片,并复制这个路径,在iis中创建一个站点物理路径指向刚才的复制的路径,端口我这里是1010,我这里没有域名只有用本机的ip代替,这里默认是localhost,配置好后,查看高级设置如:

然后点击"测试文件地址"这个站点-》内容视图 能看到如图的效果

然后,鼠标指上去右键其中某一张图片-》浏览 这样浏览器马上就能看到如图所示的效果:

这样就完成了iis发布文件夹,当然通过http访问图片只是多种方式的一种;有些后缀的文件可能访问不了,需要手动在iis中增加mime类型:

 

. 示例A - 普通表单上传文件,Request.Files获取上传文件

首先,我们来看下html主要代码:

1 <fieldset>
2             <legend>示例A - 普通表单上传文件,Request.Files获取上传文件</legend>
3             <form action="/Error/A" method="post" enctype="multipart/form-data">
4                 <input type="file" name="fileA" multiple />
5                 <button type="submit">提交</button>
6             </form>
7         </fieldset>

看是简单简单及简短的代码,其实是上传的重要部分必不可少的,下面就来简单总结下:

. form元素的action属性:表单提交地址,这里是文件上传的接口地址

. 必须采用method="post"提交方式

. 表单提交数据的格式是enctype="multipart/form-data"

. type="file"元素必须要有属性name,这里例子是name="fileA"

. type="file"元素的multiple属性可选,意思是可以选择多个上传文件不用再增加file标签元素来支持上传多个文件了,这个在近几年移动端火热的时候几乎所有最新版本浏览器都支持

再来,我们一起看下后端怎么接受表单提交过来的文件信息,先来看代码:

 1 [HttpPost]
 2         public ActionResult A()
 3         {
 4             var sbLog = new StringBuilder(string.Empty);
 5 
 6             var fileCount = Request.Files.Count;
 7             //访问上传文件地址
 8             var path = @"http://localhost:1010/{0}";
 9             //保存文件地址
10             var uploadPath = @"D:\\D\\TTest";
11             sbLog.AppendFormat("上传文件目录:{0}<br/>", uploadPath);
12             sbLog.AppendFormat("上传文件量:{0}<br/>", fileCount);
13             for (int i = 0; i < fileCount; i++)
14             {
15                 var file = Request.Files[i];
16                 if (file == null || string.IsNullOrEmpty(file.FileName)) { continue; }
17 
18                 var fileName = file.FileName;
19                 var fileNewName = DateTime.Now.Ticks + fileName;
20                 sbLog.AppendFormat("第:{0}个文件名称:{1}新名称:{2}下载地址:<a href=\'{3}\' target=\'_blank\'>{2}</a><br/>", i + 1, fileName, fileNewName, string.Format(path, fileNewName));
21                 file.SaveAs(Path.Combine(uploadPath, fileNewName));
22             }
23             return Content(sbLog.ToString());
24         }

这段代码的总要点列举如下:

. Request.Files:用来获取上传的文件,所有上传文件都以此来获取,什么文件名称也包含在列表中

. path变量:就是咋们在前面配置的iis发布文件夹的url路径,只需要传递上传的文件的名称就可以访问

. uploadPath:保存文件地址

. 通过for循环获取上传上来的文件信息和通过file.SaveAs保存到uploadPath指定的文件夹中去

. Path.Combine方法把传递进来的参数拼接长一个磁盘路径如第一个参数值是D:/第二个参数是test.png那么这个方法返回的结果是D:/test.png

最终我这个Action返回的是ContentResult,因为我想在页面输入一些信息好截图哈哈,好了咋们通过复制上面的代码运行起来点"提交"按钮得到的效果如图:

文件夹中选择上的两张图片,就是我们页面上传上来的,通过点击Action返回给页面的下载地址,我们可以在浏览器中浏览图片;好这个上传图片,浏览图片的过程描述大概就是这样,朋友们有收获一些么

 

. 示例B - 普通表单上传文件,HttpPostedFileBase获取上传文件

经过示例A描述的上传,下载图片流程应该都很清楚了,这个小节主要是换了一种获取上传文件信息的方式,我们通过HttpPostedFileBase获取(其实示例ARequest.Files的最底层就是这个),因为可能上传多个文件所以使用了IEnumerable<HttpPostedFileBase>类型来当做Action的参数,试图部分我们使用HtmlHelper的BeginForm方法来生成form标签,具体代码如:

1  <fieldset>
2             <legend>示例B - 普通表单上传文件,HttpPostedFileBase获取上传文件</legend>
3             @using (Html.BeginForm("B", "Error", FormMethod.Post, new { enctype = "multipart/form-data" }))
4             {
5                 <input type="file" name="files" multiple />
6                 <button>提交</button>
7             }
8         </fieldset>

这里使用@html.BeginForm写法主要是满足使用mvc的同学,简单说下这里使用的BeginForm参数:BeginForm(Action,Controller,表单提交方式,增加form属性enctype);好再来看下Controller的代码如:

 1 [HttpPost]
 2         public ActionResult B(IEnumerable<HttpPostedFileBase> files)
 3         {
 4             var sbLog = new StringBuilder(string.Empty);
 5 
 6             var fileCount = files == null ? 0 : files.Count();
 7             //访问上传文件地址
 8             var path = @"http://localhost:1010/{0}";
 9             //保存文件地址
10             var uploadPath = @"D:\\D\\TTest";
11             sbLog.AppendFormat("上传文件目录:{0}<br/>", uploadPath);
12             sbLog.AppendFormat("上传文件量:{0}<br/>", fileCount);
13             var i = 0;
14             foreach (var file in files)
15             {
16                 if (file == null || string.IsNullOrEmpty(file.FileName)) { continue; }
17 
18                 var fileName = file.FileName;
19                 var fileNewName = DateTime.Now.Ticks + fileName;
20                 sbLog.AppendFormat("第:{0}个文件名称:{1}新名称:{2}下载地址:<a href=\'{3}\' target=\'_blank\'>{2}</a><br/>", i + 1, fileName, fileNewName, string.Format(path, fileNewName));
21                 file.SaveAs(Path.Combine(uploadPath, fileNewName));
22             }
23             return Content(sbLog.ToString());
24         }

上面的代码与示例A对比一下,可以看出处理方式几乎是一模一样呢,那这里就没什么说的了,主要是展示下两种获取file文件信息的方式,但下面的将与众不同

 

. 示例C - ajax+FormData上传文件,Request.Files获取上传文件

首先,来了解下FormData这个近几年才被几乎所有浏览器支持的js对象,它的构造函数:new FormData (form? : HTMLFormElement),后面的?号和C#参数差不多表示参数非必须,FormData的最大优点就是可以异步上传一个二进制文件,好吧这个神奇了;继续来将示例C,通常我们提交一般的文字信息直接通过jquery的ajax,post,get等几个方法就能传递到后台,这些直接传参方式无法吧file信息传递给后台,但用到FormData我们就可以用ajax把file文件信息传递给后台,这样我们也可以有更好的无刷新效果的上传文件了,先来看下前端html代码和js代码:

<fieldset>
            <legend>示例C - ajax+FormData上传文件,Request.Files获取上传文件</legend>
            @using (Html.BeginForm("C", "Error", FormMethod.Post, new { enctype = "multipart/form-data", @id = "form_c" }))
            {
                <span>账号:</span><input type="text" name="userName" value="神牛步行3" /><br />
                <span>密码:</span><input type="password" name="userPwd" value="神牛" /><br />
                <span>文件:</span><input type="file" name="filesc" multiple /><br />
                <button type="button">提交</button><br />
                <span id="msg_c"></span>
            }
</fieldset>
<script>
    $(function () {

        //示例C代码
        $("#form_c button[type=\'button\']").click(function () {

            var msg = $("#msg_c");
            var btnSave = $(this);
            var formData = new FormData(document.getElementById("form_c"));
            console.log(formData);

            $.ajax({
                url: \'/Error/C\',
                type: \'post\',
                beforeSend: function (e) {

                    btnSave.attr("disabled", "disabled");
                    msg.html("上传中...");
                },
                success: function (data) {
                    console.log(data);
                    var alertMsg = "上传失败";
                    if (data) {
                        alertMsg = data.Status == 1 ? data.Data : alertMsg;
                    }
                    msg.html(alertMsg);
                    btnSave.removeAttr("disabled");
                },
                error: function (data) {

                    msg.html("上传失败");
                    btnSave.removeAttr("disabled");
                },
                data: formData,
                cache: false,
                contentType: false,
                processData: false
            });
        });
    })
</script>

上面的html代码与示例B的格式差不多,只是增加了两个input元素方便我们来测试;重点在js代码中,由上面介绍可以看到FormData的构造只能是HTMLFormElement,所以我们通过document.getElementById("form_c")来获取这个表单的对象传递给它;

然后,我们用普通的$.ajax提交FormData对象到后台进行上传,至于后台我们参照示例A的方式来获取文件信息,不用做什么特殊额处理,只是我们返回的信息是Json数据,代码如:

 1 [HttpPost]
 2         public JsonResult C()
 3         {
 4             Thread.Sleep(1000 * 5);
 5             var response = new MoResponse();
 6             var sbLog = new StringBuilder("开始处理...");
 7             try
 8             {
 9 
10                 sbLog.AppendFormat("账号:{0}<br/>", Request.Params["userName"]);
11                 sbLog.AppendFormat("密码:{0}<br/>", Request.Params["userPwd"]);
12 
13                 var fileCount = Request.Files.Count;
14                 //访问上传文件地址
15                 var path = @"http://localhost:1010/{0}";
16                 //保存文件地址
17                 var uploadPath = @"D:\\D\\TTest";
18                 sbLog.AppendFormat("上传文件目录:{0}<br/>", uploadPath);
19                 sbLog.AppendFormat("上传文件量:{0}<br/>", fileCount);
20                 for (int i = 0; i < fileCount; i++)
21                 {
22                     var file = Request.Files[i];
23                     if (file == null || string.IsNullOrEmpty(file.FileName)) { continue; }
24 
25                     var fileName = file.FileName;
26                     var fileNewName = DateTime.Now.Ticks + fileName;
27                     sbLog.AppendFormat("第:{0}个文件名称:{1}新名称:{2}下载地址:<a href=\'{3}\' target=\'_blank\'>{2}</a><br/>", i + 1, fileName, fileNewName, string.Format(path, fileNewName));
28                     file.SaveAs(Path.Combine(uploadPath, fileNewName));
29                     response.Status = 1;
30                 }
31             }
32             catch (Exception ex)
33             {
34                 sbLog.AppendFormat("异常信息:{0}", ex.Message);
35             }
36             finally
37             {
38                 response.Data = sbLog.ToString();
39             }
40             return Json(response);
41         }
View Code

下面我们看一下添加"提交"按钮执行后返回的效果,可以看出提交后没有跳转到action指向的路由,这样用户体验就好多了:

. 示例D - 自定义上传插件,Request.Files获取上传文件并提交表单内容

首先,我发个插件下载地址shenniu.upfile-0.0.1.js,只需要在试图或者html页面引用jquery-1.10.2.min.js库和这个插件,我们就可以这样使用:

 1 <script>
 2     $(function () {
 3 
 4         //示例D代码
 5         //初始化插件
 6         var shenniu = new shenniu_UpFile({
 7 
 8             url: "/Error/D_A",
 9             fileEleName: "filesd"
10         });
11 
12         //提交事件
13         $("#form_d button[type=\'button\']").click(function () {
14 
15             var msg = $("#msg_d");
16             var btnSave = $(this);
17             btnSave.attr("disabled", "disabled");
18             msg.html("上传中..");
19 
20             //上传文件
21             shenniu.submitFun(function (data) {
22 
23                 try {
24 
25                     var result = JSON.parse(data);
26                     //上传成功,保存数据
27                     if (result.Status == 1) {
28 
29                         //增加上传成功的文件名称到表单
30                         var hidFileNames = $("#form_d input[name=\'hidFileNames\']");
31                         if (hidFileNames.length <= 0) { $("#form_d").append("<input type=\'hidden\' name=\'hidFileNames\' value=\'" + result.Data + "\'/>"); }
32                         else {
33                             hidFileNames.val(result.Data);
34                         }
35 
36                         //获取表单键值对,提交表单数据
37                         var param = $("#form_d").serialize();
38                         var action = $("#form_d").attr("action");
39                         $.post(action, param, function (res) {
40 
41                             msg.html(res.Status == 1 ? "保存成功<br/>" + res.Data : "保存失败");
42                         });
43 
44                     } else {
45 
46                         msg.html(result.Data);
47                     }
48                 } catch (e) {
49                     console.log(e.message);
50                 } finally {
51                     btnSave.removeAttr("disabled");
52                 }
53             });
54         });
55     })
56 </script>

使用插件的地方和js关键点已经通过代码注释备注好了,朋友们可仔细阅读下,这里要将的是插件上传文件和提交表单数据的逻辑;我们分析下:

. form表单中通常有其他的属性数据

. form表单的提交数据的后台地址可能和上传文件的后台地址不一样

. 需要单独上传文件后,返回是否上传成功,再提交form表单的其他数据到后台

由上面几点插件的参数定义为:

1  var defOption = {
2 
3         url: "http://www.cnblogs.com/wangrudong003/",   //上传路由地址,注:1.目前通过该地址上传文件成功后,返回的信息是text/plain  2.跨域暂未考虑
4         fileEleName: "fileName",                        //上传input file控件的唯一名称
5         uid: new Date().getTime(),                      //防重复
6         backFun: function () { }                         //回调函数
7     };

这个自定义插件原理和几个重点是:

. 自动创建一个iframe(用来做无刷新体验),iframe里面创建一个form表单,form表单里面只包含要上传的文件file对象,最终把iframe加入到视图页面中

. 通过iframe.load()方法来获取上传文件后返回到contentWindow.document.body中的信息,并且执行自定义回调函数,把参数传递给自定义方法方便使用者自由的控制体验效果

. 创建的form表单里面只能使用页面选择文件上传的文件file对象,使用jquery的clone()函数无法获取到选择的文件对象(这是一个悲剧),所以我这个使用append把用户使用的那个file对象直接包含到创建的form中去,然后在创建一个初始化的file元素对象到原始的视图中去代替被移除掉的file元素,代码如(这个还真花了我2个小时的时间尝试):

1             //清空自定义form多余的file元素
2             form.html("");
3             var files = $("input[name=\'" + defOption.fileEleName + "\']");
4             //复制上传控件对象
5             var filesClone = files.clone(true);
6             filesClone.insertAfter(files);
7             form.append(files);

. 使用该插件提交原始表单数据的顺序是:用户点击页面的保存按钮-》通过插件创建的上传文件的form表单,提交上传文件-》上传文件返回成功与否的信息-》收到上传成功新文件名称信息,创建个hidden保存新文件名称到原始form中去-》再真实提交原始form表单的其他数据

下面来看下效果图:

示例D的后台代码分为两部分:1.上传文件的Action 2.真实获取表单form参数的Action,代码如:

 1  /// <summary>
 2         /// 保存form提交的表单数据
 3         /// </summary>
 4         /// <returns></returns>
 5         [HttpPost]
 6         public JsonResult D()
 7         {
 8             var response = new MoResponse();
 9             var sbLog = new StringBuilder(string.Empty);
10             try
11             {
12                 //访问上传文件地址
13                 var path = @"http://localhost:1010/{0}";
14                 sbLog.AppendFormat("账号:{0}<br/>", Request.Params["userName"]);
15                 sbLog.AppendFormat("密码:{0}<br/>", Request.Params["userPwd"]);
16                 foreach (var item in Request.Params["hidFileNames"].Split(new char[] { \'|\' }, StringSplitOptions.RemoveEmptyEntries))
17                 {
18                     sbLog.AppendFormat("文件新名称:{0};下载地址:<a href=\'{1}\' target=\'_blank\'>{0}</a><br/>", item, string.Format(path, item));
19                 }
20                 response.Status = 1;
21             }
22             catch (Exception ex)
23             {
24                 sbLog.AppendFormat("异常信息:{0}", ex.Message);
25             }
26             finally
27             {
28                 response.Data = sbLog.ToString();
29             }
30             return Json(response);
31         }
32 
33 
34         /// <summary>
35         /// 获取上传文件信息
36         /// </summary>
37         /// <returns></returns>
38         [HttpPost]
39         public ContentResult D_A()
40         {
41             var response = new MoResponse();
42             response.Data = "上传失败";
43             try
44             {
45                 Thread.Sleep(1000 * 3);
46                 var fileCount = Request.Files.Count;
47                 //保存文件地址
48                 var uploadPath = @"D:\\D\\TTest";
以上是关于文件上传的几个 - 示例的主要内容,如果未能解决你的问题,请参考以下文章

记录小文件上传的几个例子(含进度条效果,附源码下载)

H5前端上传文件的几个解决方案

图片上传功能的几个工具类的介绍

qq企业邮箱的几个有用的功能

使 PHP 代码更加简洁的几个小技巧

PHP文件上传代码用法