【转】文件各类上传,离不开的表单

by admin on 2018年12月25日

图表发自与花瓣网

【转】文件各种上传,离不开的表单

文❤这何人菇凉

作为程序员的我们,平常会要用到文件的上传和下载效率。到了需要用的时候,各样查资料。有木有..有木有…。为了有利于下次应用,这里来做个总计和备忘。

任凭是柔情仍然友情,和什么人舒服,就和谁在一块儿。

运用表单实现文件上传

最原始、最简便易行、最粗暴的文本上传。
前者代码:

//方式1
<form action="/Home/SaveFile1" method="post" enctype="multipart/form-data">
     <input type="file" class="file1" name="file1" />
     <button type="submit" class="but1">上传</button>
</form>

【注意】

  • 1、需要post提交
  • 2、enctype=”multipart/form-data” (传输文件)
  • 3、需要提交的表单元素需要设置 name 属性

后台代码:

public ActionResult SaveFile1()
{
    if (Request.Files.Count > 0)
    {
        Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Request.Files[0].FileName);
        return Content("保存成功");
    }
    return Content("没有读到文件");
}

01

表单异步上传(jquery.form插件)

即便如此下面的主意简单粗暴,不过不够协调。页面必然会刷新。难以实现停留在眼前页面,并交给文件上传成功的唤醒。
乘胜时间的流逝,技术日新月异。ajax的面世,使得异步文件提交变得更为容易。
下边我们利用jquery.form插件来兑现文件的异步上传。
第一大家需要导入jquery.jsjquery.form.js
前者代码:

<form id="form2" action="/Home/SaveFile2" method="post" enctype="multipart/form-data">
    <input type="file" class="file1" name="file1" />
    <button type="submit" class="but1">上传1</button>
    <button type="button" class="but2">上传2</button>
</form>

//方式2(通过ajaxForm绑定ajax操作)
$(function () {
    $('#form2').ajaxForm({
        success: function (responseText) {
            alert(responseText);
        }
    });
});

//方式3(通过ajaxSubmit直接执行ajax操作)
$(function () {
    $(".but2").click(function () {
        $('#form2').ajaxSubmit({
            success: function (responseText) {
                alert(responseText);
            }
        });
    });
});

后台代码:

public string SaveFile2()
{
    if (Request.Files.Count > 0)
    {                
        Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName));
        return "保存成功";
    }
    return "没有读到文件";
}

原理:
我们广大时候使用了插件,就不管其他三七二十一吧。
如若有点好奇心,想想那一个插件是怎么落实的。随便看了看源码一千五百多行。我的妈啊,不就是个异步上传吗,怎么如此复杂。
不便见到个怎么着鬼来,直接断点调试下吧。
图片 1
本来插件内部有iframe和FormData不同方法来上传,来适应更多版本浏览器。

小帆因为家长的掣肘,和恋爱七年的阿鑫分别了。

如法炮制表单数据上传(FormData)

iframe这东西太恶心。大家看出上边可以应用FormData来上传文件,这个是Html 5
才有的。上面大家自己也来试试看把。
前端代码:

<input id="fileinfo" type="file" class="notFormFile" />
<button type="button" class="btnNotForm">上传4</button>

//方式4
$(".btnNotForm").click(function () {
    var formData = new FormData();//初始化一个FormData对象
    formData.append("files", $(".notFormFile")[0].files[0]);//将文件塞入FormData
    $.ajax({
        url: "/Home/SaveFile2",
        type: "POST",
        data: formData,
        processData: false,  // 告诉jQuery不要去处理发送的数据
        contentType: false,   // 告诉jQuery不要去设置Content-Type请求头
        success: function (responseText) {
            alert(responseText);
        }
    });
});

后的代码:(不变,依然上例代码)

public string SaveFile2()
{
    if (Request.Files.Count > 0)
    {                
        Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName));
        return "保存成功";
    }
    return "没有读到文件";
}

我们看看,FormData对象也只是在模拟一个本来的表单格式的多寡。这有没有可能不应用表单或表单格式来上传文件呢?答案是大势所趋的。(下边登时宣布)
前者代码:

<input type="file"  id="file5" multiple>
<button type="button" class="btnFile5">上传5</button>    

//方式5
$(".btnFile5").click(function () {
    $.ajax({
        url: "/Home/SaveFile4",
        type: "POST",
        data: $("#file5")[0].files[0],
        processData: false,  // 告诉jQuery不要去处理发送的数据
        contentType: false,   // 告诉jQuery不要去设置Content-Type请求头
        success: function (responseText) {
            alert(responseText);
        }
    });;       
});       

后台代码:

public string SaveFile4()
{
    //这里发现只能得到一个网络流,没有其他信息了。(比如,文件大小、文件格式、文件名等)
    Request.SaveAs(Server.MapPath("~/App_Data/SaveFile4.data") + "", false);
    return "保存成功";
}

仔细的您发现并未了表单格式,我们除了可以上传文件流数据外,不可能再报告后台其他音讯了(如文件格式)。
到这边,我似乎知道了从前上传文件为什么非得要用个form包起来,原来这只是和后台约定的一个传输格式而已。
实在大家只有的用jq的ajax传输文本数据的时候,最终也是组建成了form格式的数额,如:

 $.ajax({
    data: { "userName": "张三" } 

因为阿鑫工作不安静,在他父母看来,他不可能给小帆更好的前景。

分片上传

在明亮了地方的各类上传之后,大家是不是就满于现状了吧?no,很多时候我们需要传输大文件,一般服务器都会有早晚的大大小小限制。
某天,你发觉了一个心理小电影想要分享个大家。无奈,高清文件太大传不了,如何是好?我们得以化整为零,一部分部分的传嘛,也就是所谓的分片上传。
前者代码:

<input type="file" id="file6" multiple>
<button type="button" class="btnFile6">分片上传6</button>
<div class="result"></div>

//方式6
 $(".btnFile6").click(function () { 
     var upload = function (file, skip) {
         var formData = new FormData();//初始化一个FormData对象
         var blockSize = 1000000;//每块的大小
         var nextSize = Math.min((skip + 1) * blockSize, file.size);//读取到结束位置             
         var fileData = file.slice(skip * blockSize, nextSize);//截取 部分文件 块
         formData.append("file", fileData);//将 部分文件 塞入FormData
         formData.append("fileName", file.name);//保存文件名字
         $.ajax({
             url: "/Home/SaveFile6",
             type: "POST",
             data: formData,
             processData: false,  // 告诉jQuery不要去处理发送的数据
             contentType: false,   // 告诉jQuery不要去设置Content-Type请求头
             success: function (responseText) {
                 $(".result").html("已经上传了" + (skip + 1) + "块文件");
                 if (file.size <= nextSize) {//如果上传完成,则跳出继续上传
                     alert("上传完成");
                     return;
                 }
                 upload(file, ++skip);//递归调用
             }
         });
     };

     var file = $("#file6")[0].files[0];
     upload(file, 0);
 }); 

后台代码:

public string SaveFile6()
{
    //保存文件到根目录 App_Data + 获取文件名称和格式
    var filePath = Server.MapPath("~/App_Data/") + Request.Form["fileName"];
    //创建一个追加(FileMode.Append)方式的文件流
    using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write))
    {
        using (BinaryWriter bw = new BinaryWriter(fs))
        {
            //读取文件流
            BinaryReader br = new BinaryReader(Request.Files[0].InputStream);
            //将文件留转成字节数组
            byte[] bytes = br.ReadBytes((int)Request.Files[0].InputStream.Length);
            //将字节数组追加到文件
            bw.Write(bytes);
        }
    }
    return "保存成功";
}

对立而言,代码量多了一点,复杂了一点。然而绝对于网上的其它分片上传的代码应该要简明得多(因为此处没有设想多文件块同时上传、断点续传。这样就需要在后台把公文块排序,然后上传完成按序合并,然后删除原来的临时文件。有趣味的同校可以自己摸索,稍候在条分缕析上传插件webuploader的时候也会实现)。
效果图:
图片 2
【表明】:假诺我们想要上传三个公文咋办?其实H5中也提供了异常简单的法子。直接在input内部标记multiple<input type="file" id="file6" multiple>,然后大家后台接受的也是一个数组Request.Files

就如此,一对相爱的情人被父母棒打了鸳鸯。

接纳HTML5 拖拽、粘贴上传

不得不说H5真是强大啊,权限越来越大,操作更是牛逼。
前者代码(拖拽上传):

<textarea class="divFile7" style="min-width:800px;height:150px" placeholder="请将文件拖拽或直接粘贴到这里"></textarea>

//方式7
 $(".divFile7")[0].ondrop = function (event) {

     event.preventDefault();//不要执行与事件关联的默认动作
     var files = event.dataTransfer.files;//获取拖上来的文件

     //以下代码不变
     var formData = new FormData();//初始化一个FormData对象
     formData.append("files", files[0]);//将文件塞入FormData
     $.ajax({
         url: "/Home/SaveFile2",
         type: "POST",
         data: formData,
         processData: false,  // 告诉jQuery不要去处理发送的数据
         contentType: false,   // 告诉jQuery不要去设置Content-Type请求头
         success: function (responseText) {
             alert(responseText);
         }
     });
 };

后台代码:
略(和事先的SaveFile2一样)

前者代码(粘贴上传 限图片格式):

//方式8
$(".divFile7")[0].onpaste = function (event) {
    event.preventDefault();//不要执行与事件关联的默认动作
    var clipboard = event.clipboardData.items[0];//剪贴板数据
    if (clipboard.kind == 'file' || clipboard.type.indexOf('image') > -1) {//判断是图片格式
        var imageFile = clipboard.getAsFile();//获取文件

        //以下代码不变
        var formData = new FormData;
        formData.append('files', imageFile);
        formData.append('fileName', "temp.png");//这里给文件命个名(或者直接在后台保存的时候命名)
        $.ajax({
            url: "/Home/SaveFile8",
            type: "POST",
            data: formData,
            processData: false,  // 告诉jQuery不要去处理发送的数据
            contentType: false,   // 告诉jQuery不要去设置Content-Type请求头
            success: function (responseText) {
                alert(responseText);
            }
        });
    }
};

后台代码:

public string SaveFile8()
{
    //保存文件到根目录 App_Data + 获取文件名称和格式
    var filePath = Server.MapPath("~/App_Data/") + Request.Form["fileName"];      
    if (Request.Files.Count > 0)
    {
        Request.Files[0].SaveAs(filePath);
        return "保存成功";
    }
    return "没有读到文件";
}

效果图:
图片 3

她同意了大人的布局,和知心对象相会。

上传插件(WebUploader)

现已列举分析了多种上传文件的点子,我想总有一种适合您。但是,上传这一个效率相比较通用,而我辈和好写的可能过多动静没有设想到。接下来简单介绍下百度的WebUploader插件。
比起大家协调写的简要上传,它的优势:稳定、兼容性好(有flash切换,所以协助IE)、效能多、并发上传、断点续传(紧要仍然靠后台配合)。
官网:http://fex.baidu.com/webuploader/
插件下载:https://github.com/fex-team/webuploader/releases/download/0.1.5/webuploader-0.1.5.zip
下边开头对WebUploader的行使
先是种,简单粗暴
前端代码:

<div id="picker">选择文件</div>
<button id="ctlBtn" class="btn btn-default">开始上传</button>

<!--引用webuploader的js和css-->
<link href="~/Scripts/webuploader-0.1.5/webuploader.css" rel="stylesheet" />
<script src="~/Scripts/webuploader-0.1.5/webuploader.js"></script>
<script type="text/javascript">
    var uploader = WebUploader.create({

        // (如果是新浏览器 可以不用 flash)
        //swf: '/Scripts/webuploader-0.1.5/Uploader.swf',

        // 文件接收服务端。
        server: '/Webuploader/SaveFile',

        // 选择文件的按钮。可选。
        // 内部根据当前运行是创建,可能是input元素,也可能是flash.
        pick: '#picker'
    });

    $("#ctlBtn").click(function () {
        uploader.upload();
    });

    uploader.on('uploadSuccess', function (file) {
        alert("上传成功");
    });

</script>

后台代码:

public string SaveFile()
{
    if (Request.Files.Count > 0)
    {
        Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName));
        return "保存成功";
    }
    return "没有读到文件";
}

第二种,分片上传。和大家前边自己写的职能差不多。
前者代码:

var uploader = WebUploader.create({ 
    //兼容老版本IE
    swf: '/Scripts/webuploader-0.1.5/Uploader.swf', 
    // 文件接收服务端。
    server: '/Webuploader/SveFile2', 
    // 开起分片上传。
    chunked: true, 
    //分片大小
    chunkSize: 1000000, 
    //上传并发数
    threads: 1,
    // 选择文件的按钮。 
    pick: '#picker'
});

// 点击触发上传
$("#ctlBtn").click(function () {
    uploader.upload();
});

uploader.on('uploadSuccess', function (file) {
    alert("上传成功");
});

后台代码:

public string SveFile2()
{
    //保存文件到根目录 App_Data + 获取文件名称和格式
    var filePath = Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName);
    //创建一个追加(FileMode.Append)方式的文件流
    using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write))
    {
        using (BinaryWriter bw = new BinaryWriter(fs))
        {
            //读取文件流
            BinaryReader br = new BinaryReader(Request.Files[0].InputStream);
            //将文件留转成字节数组
            byte[] bytes = br.ReadBytes((int)Request.Files[0].InputStream.Length);
            //将字节数组追加到文件
            bw.Write(bytes);
        }
    }
    return "保存成功";
}

咱俩看看了有个参数threads: 1上传并发数,如若大家改成大于1会怎么样?前端会同时提倡四个文件片上传。后台就会报错,五个过程同时操作一个文书。
这假设大家想要多线程上传如何做?改代码吧(紧如果后台逻辑)。
前者代码:

//并发上传(多线程上传)
var uploader = WebUploader.create({
    //兼容老版本IE
    swf: '/Scripts/webuploader-0.1.5/Uploader.swf',
    // 文件接收服务端。
    server: '/Webuploader/SveFile3',
    // 开起分片上传。
    chunked: true,
    //分片大小
    chunkSize: 1000000,
    //上传并发数
    threads: 10,
    // 选择文件的按钮。
    pick: '#picker'
});

// 点击触发上传
$("#ctlBtn").click(function () {
    uploader.upload();
});

uploader.on('uploadSuccess', function (file) {
    //上传完成后,给后台发送一个合并文件的命令
    $.ajax({
        url: "/Webuploader/FileMerge",
        data: { "fileName": file.name },
        type: "post",
        success: function () {
            alert("上传成功");
        }
    });
});

后台代码:

public string SveFile3()
{
    var chunk = Request.Form["chunk"];//当前是第多少片 

    var path = Server.MapPath("~/App_Data/") + Path.GetFileNameWithoutExtension(Request.Files
    if (!Directory.Exists(path))//判断是否存在此路径,如果不存在则创建
    {
        Directory.CreateDirectory(path);
    }
    //保存文件到根目录 App_Data + 获取文件名称和格式
    var filePath = path + "/" + chunk;
    //创建一个追加(FileMode.Append)方式的文件流
    using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write))
    {
        using (BinaryWriter bw = new BinaryWriter(fs))
        {
            //读取文件流
            BinaryReader br = new BinaryReader(Request.Files[0].InputStream);
            //将文件留转成字节数组
            byte[] bytes = br.ReadBytes((int)Request.Files[0].InputStream.Length);
            //将字节数组追加到文件
            bw.Write(bytes);
        }
    }           
    return "保存成功";
}

/// <summary>
/// 合并文件
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public bool FileMerge()
{
    var fileName = Request.Form["fileName"];
    var path = Server.MapPath("~/App_Data/") + Path.GetFileNameWithoutExtension(fileName);

    //这里排序一定要正确,转成数字后排序(字符串会按1 10 11排序,默认10比2小)
    foreach (var filePath in Directory.GetFiles(path).OrderBy(t => int.Parse(Path.GetFileNameWithoutExtension(t))))
    {
        using (FileStream fs = new FileStream(Server.MapPath("~/App_Data/") + fileName, FileMode.Append, FileAccess.Write))
        {
            byte[] bytes = System.IO.File.ReadAllBytes(filePath);//读取文件到字节数组
            fs.Write(bytes, 0, bytes.Length);//写入文件
        }
        System.IO.File.Delete(filePath);
    }
    Directory.Delete(path);
    return true;
}

到此地你觉得就结束了啊?错,还有不少气象没有设想到。假设五个用户上传的文书名字同样会如何?如何实现断点续传?还没兑现选取六个文本?然则,这里不打算继续贴代码了(再贴下去,代码量越来越多了),自己也来锻炼训练吧。
提供一个思路,上传前先往数据库插入一条数据。数据包含文件要存的门路、文件名(用GUID命名,避免同名文件冲突)、文件MD5(用来辨别下次续传和秒传)、临时文件块存放路径、文件是否完整上传成功等音信。
接下来假诺大家断网后再传,首先拿到文件MD5值,看数据库里面有没上传完成的文件,假诺有就兑现秒传。假如没有,看是不是有上传了部分的。假设有接着传,即使没有则另行传一个新的公文。

对方一表人才,有车有房,条件优越,前途一片光明。

总结

事先自己一直很疑惑,为啥上传文件一定要用form包起来,现在算是大概知道了。
最开端在javascript还不流行时,大家就足以一向利用submit按钮提交表单数据了。表单里面可以涵盖文字和文件。然后趁机js和ajax的风行,可以应用ajax直接异步提交部分表单数据。那里伊始自我就纠结了,为何ajax可以交到自己组装的数据。这为何无法直接提交文件呢。这里我错了,ajax提交的并不是随机的数目,最后如故组装成了表单格式(因为后台技术对表单格式数据的补助相比普及)。可是现有的技能还不可以经过js组装一个文件格式的表单数据。直到H5中的FormData出现,让前端js组装一个蕴含文件的表单格式数据变成了说不定。所以说表单只是为着知足和后台“约定”的数目格式而已。

 

连锁推荐

demo

 

她对小帆呵护倍加,下班了就带他出去玩,公园、游戏场、滑冰场等等。

老是去的地点都不同等,变着法得哄小帆掀拳裸袖。

就餐的时候,对方车接车送,小帆不用再挤公交受罪。

五次约会之后,小帆对她的映像不错。

不过交往了不到六个月,小帆仍旧不曾爱上他,就提议了分离。

因为她不敢想象,即便采取嫁给这个男人,这他的终身该是有多么苦痛。

02

本人问她问哪些?

她说,也许人的年华越来越大,我仿佛很难再爱上一个人。

他很好,帅气可爱,幽默风趣,珍视温柔,是两全伴侣的最佳人选。

而是,我和她在一道的时候,总是感到少了点什么?

是一种很不好受的痛感,在她眼前,我不可以一心做协调。

然则在阿鑫后面我却不是如此的。

我会在阿鑫前面撒娇,无理取闹,任性妄为,说出自己的感触和想方设法,而不是像在他前头一言不发。

从而,小帆决定和对方分手,和阿鑫复合。

她说,这四回,不管家长在咋样阻隔,她都会坚决自己的拔取。

03

自身晓得小帆口中所说的这种痛感。

因为爱好一个人,我们在她前头不需要伪装,想哭就大声的哭,想笑就大声的笑,因为清楚对方不会在意。

就像小帆和阿鑫相同,他们在协同的时候,会很自在,很满意,很轻松。

而不是紧绷着神经,深怕自己做错了如何事,对方会讨厌自己一样。

不怕在他前方挖鼻孔,扣脚趾,也是一件毫无避讳的事情。

在对方眼里,你的那一个小动作依然是讨人喜欢的行事。

大家不需要去刻意逢迎,过于在乎对方的感受,强颜欢笑,弄得温馨身心疲倦。

04

有点人,在局别人面前总是一副高冷的规范,其实不然,只是每户和你不熟而已。

平等的,人家也不是特意掩饰,只是放不开而已。

就此,你看不到她的微笑,她在熟人面前如脱兔般的模样。

好的一端都是面对旁人的,像那一个所谓的礼貌、客套、坚强等。

只有最本真的一面是留给亲近的人。

在您面前,尽管自己在能死磕,遭逢难过的坎,也会想要一头扑到你的怀里哭得像小孩,不要什么所谓的顽强。

在外围怎样咋样风光靓丽,是个女强人,可是在您面前,依然想要做个永远长不大的小公主,让你宠,让你哄。

因为,和您在协同,我是当真在做和好,不是伪装很欣喜。

江湖已经这样不易于了,一定要找个能让您依靠和让您感觉舒适的胸怀。

05

学妹雅儿目前像自己吐口水,因为任何宿舍的人都在排斥她,她老是不加入公共移动。

在开宿舍晌午社团睡衣大会,她因为一天的疲劳早已昏昏欲睡。

在宿舍的姊妹们去外聚餐涮火锅的时候,她因为和朋友在外做义务劳动没有赶回去。

在宿舍集体出来逛街买买买的时候,她和在公司活动时的同伴相约去爬山。

雅儿说,不是他不想和她们在一起耍,只是她一度努力去融入她们的园地,但实质上是兴趣不合,退步了。

雅儿说,她刚起头的时候,也感到自己很害羞,作为宿舍的一员,她老是缺席。

故而,她想了挽救措施,就是主动拉进她们之间的相距。

雅儿很用力的想要和他们相处,然而在她们后边,她很累。

室友们商讨的影星是她不认识的,八卦的电视剧是他没追过的,花痴的帅哥也是他不感兴趣的。

但他依旧假装一副很迎合的神态,参预到他俩可以的议论中去。

坚贞不屈不懈了不到一礼拜,她就放弃了。

理由就是,和她们相处真的是太不好受了。

06

雅儿近期退出了他们的集体,感觉就像是从牢笼里解放出的小鸟一样,呼吸到干净的气氛,天高任鸟阔。

她又卷土重来了原本的活着,和投机的同伴,天天泡体育场馆,偶尔出去爬爬山。

和让您不舒服的人在一块,就像是把你身处一个热闹非凡的庙会,狂欢盛典,你却是孤独难耐。

因此,圈子不同,不必强融。

这么些让您不舒服的人实则是与您的三观不等同。

在您眼里,大海很美,而在对方眼里,它淹死过众四人。

尚无何人对什么人错,只是三观不雷同一样而已。

好的情爱相对是锦上添花的,好的情谊也是高山流水,相见恨晚的。

不论爱情,如故友情,和这多少个能让你倍感到舒服的人在一块儿。

无戒365极限日更挑战营 第69天

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图