zoukankan      html  css  js  c++  java
  • 上传文件 file upload 学习笔记

    这里我只会说说一些完成 file upload 的基础 API。

    很多项目我们需要上传文件。

    有简单的 input file, 有需要验证的,有需要压缩的(img),有需要分段的(video),有需要体验好(display on local, ajax & percent) 等等

    要完成以上的所有需求,我们需要很多底层的 API, 比如 File, FileReader, Canvas , XMLHttpRequest , Blob

    要把这个控件写好的话,需要一些设计模式,不过这篇不会涉及这个,我只是想大略的说说过程和使用到的API方法,如何去设计就交给你们自己了。

    参考 : 

    http://javascript.ruanyifeng.com/bom/ajax.html

    http://www.html5rocks.com/zh/tutorials/file/dndfiles/

    https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL

    http://www.w3schools.com/tags/canvas_drawimage.asp

    https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice

    http://www.codicode.com/art/upload_and_save_a_canvas_image_to_the_server.aspx

    基本的步骤是这样的

    1. input file addEventListener change 监听 input file (你要用 drag drop 替代也行)

    2. 得到 file 对象之后你就可以检查 file.name,file.type,file.size 等等了

    3. 我可以通过 FileReader.readAsDataURL(file); 来获取一个 base64 string (这个是针对图片的处理,如果是txt的话你可以用别的 FileReader.readAs...其它)

    4. 把这个 base64 放入img.src = base64 的话就可以在本地显示图片了

    5. 在打开一个canvas 后,我们可以把上面的这张相片放入 canvas , 修改它的尺寸,加水印等等.

    6. canvas.toDataURL() 把图像转换回 base64 string.

    7. 通过XMLHttpRequest 上传这个 base64 string. (XMLHttpRequest 可以监听 process percent)

    8. 后端把 base64 convert to byte 写入 fileStream 就完成了。 

    如果要支持分段上传的话,base64应该直接substring记入index position 就可以了。

    如果上传的是 file 不是 base64 的话,可以使用 Blob.webkitSlice() | Blob.slice 

    document.getElementById("file").addEventListener("change", function (e) {
        var files = S.toArray(this.files);
        var file = files[0];               
        var fileReader = new FileReader();
    
        fileReader.onloadend = function (e) {    
            var img = new Image();
            img.onload = function () {
                //比例要是尺寸
                var MAX_WIDTH = 2560 / 2;
                var canvas = document.getElementById("canvas");                                             
                var context = canvas.getContext("2d");                                         
                var height = this.height * (MAX_WIDTH / this.width);
                canvas.width = MAX_WIDTH;
                canvas.height = height;
                //画图
                //参数就是把img 的x,y,widthLength,heightLength copy 
                //然后 paste to canvas 的 x,y,widthLength,heightLength
                context.drawImage(this, 0, 0, this.width, this.height, 0, 0, MAX_WIDTH, height); 
    
                var base64 = canvas.toDataURL("image/jpeg", 0.8); //default 会是 png 格式,第2参数是压缩质量 0-1 (png 不可以压缩)
                base64 = base64.replace(/^data:image/(png|jpeg);base64,/, ""); //后端保存的时候不可以有前面这些字,所以在这里先去除
                        
                var http = new XMLHttpRequest();
                var formData = new FormData(); 
                formData.append("file", base64);
                http.open("POST", "//localhost:8054/module/Upload/UploadAjax.ashx", true);
                http.onreadystatechange = function () {
                    if (this.readyState == 4) {
                        if (this.status == 200) {
                            var imgSrc = this.responseText;
                        }
                        else if (this.status == 0) { //abort 会"同步"执行这里 
    
                        }
                        else {
                            log("file upload ajax fail, looping upload stoped. statusCode : " + this.status);
                        }
                    }
                }
                http.upload.onprogress = function (e) {
                    if (e.lengthComputable) {
                        var percent = parseFloat(e.loaded / e.total * 100).toFixed(0); //八仙                             
                    }
                }
                http.send(formData);
            }
            img.src = this.result;
        }
        fileReader.readAsDataURL(file);
    
    }, false);
    //upload base64 的处理
    string path = context.Server.MapPath(@"~img" + "abc.jpeg");
    using (FileStream fs = new FileStream(path, FileMode.Create))
    {
        using (BinaryWriter bw = new BinaryWriter(fs))
        {
            byte[] data = Convert.FromBase64String(context.Request.Form["file"]);                    
            bw.Write(data);
            bw.Close();
        }
    }
    context.Response.ContentType = "text/plain";
    context.Response.Write(path);
    //update file 的处理
    string[] fileKeys = context.Request.Files.AllKeys;
    string fileName = "";
    foreach (string fileKey in fileKeys)
    {
        HttpPostedFile file = context.Request.Files[fileKey];
        string extension = "." + file.ContentType.Substring(6);
        //string extension = file.FileName.Substring(file.FileName.LastIndexOf("."));
        fileName = Guid.NewGuid() + extension;
        file.SaveAs(context.Server.MapPath(@"~img" + fileName));
    }
    context.Response.ContentType = "text/plain";
    context.Response.Write(fileName);

    有一点要说明一下,canvas to base64 png 的话,size 是非常大的, 比源文件还要大的多,所以png 格式是不能通过canvas做压缩的. (如果我错了,请告诉我)

    所以一般上我们是对jpeg做压缩, 质量设置成0.92 的话,size 会和源文件相同. 不过0.92并不是default的设置,default设置会再低一些。

    上面我没有实现水印和分段,以后等我有时间写一个完整的控件时,我才更新。

  • 相关阅读:
    在vue中使用pug
    【心无旁骛】vuex-simple
    Property 'validate' does not exist on type 'Element | Element[] | Vue | Vue[]'. Property 'valid...
    【心无旁骛】vue-ts-daily
    Vuex持久化存储之vuex-persist
    canvas 水滴图、液体进度条、仿加速球、圆球水波图
    stackoverflow愚人节彩蛋效果
    Windows平台网站图片服务器架构的演进[转]
    SQL Server AlwaysOn架构及原理
    AlwaysON同步的原理及可用模式
  • 原文地址:https://www.cnblogs.com/keatkeat/p/4419327.html
Copyright © 2011-2022 走看看