zoukankan      html  css  js  c++  java
  • html大文件分片传输

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用。

    首先我们需要了解的是上传文件三要素:

    1.表单提交方式:post (get方式提交有大小限制,post没有)

    2.表单的enctype属性:必须设置为multipart/form-data.

    3.表单必须有文件上传项:file,且文件项需要给定name值

    上传文件夹需要增加一个属性webkitdirectory,像这样:

    不过webkitdirectory属性有个问题,只能支持高版本的chrome,不能支持低版本的IE,如ie6,ie7,ie8,不能做到全浏览器适配,运行环境比较单一。

    js中可以判断文件夹中文件数量及文件夹大小是否符合要求,不符合要求不能向后台提交:

    前台HTML模板

    this.GetHtmlFiles = function()

    {

         var acx = "";

         acx += '

                    

                       

                           

                                

    HttpUploader程序开发.pdf

                                

    (35%)

                                

    1000.23MB

                        

                           

     

                           

    15.3MB 20KB/S 10:02:00

                       

                       

                        

    取消

                        

    继续

                           

    停止

                           

    删除

                       

    ';

         acx += '

    ';

         //文件夹模板

         acx += '

                       

                       

                           

                                

    HttpUploader程序开发.pdf

                                

    (35%)

                                

    1000.23MB

                        

                           

     

                           

    15.3MB 20KB/S 10:02:00

                       

                       

                        

    取消

                        

    继续

                           

    停止

                           

    删除

                       

    ';

         acx += '

    ';

         //上传列表

         acx += '

                       

                           选择多个文件

                           选择文件夹

                           粘贴文件和目录

                           安装控件

                       

                       

                           

     

                       

                       

                  

    ';

         return acx;

    };

    选择文件,选择文件夹,粘贴文件和文件夹的逻辑

    this.open_files = function (json)

    {

         for (var i = 0, l = json.files.length; i < l; ++i)

        {

             this.addFileLoc(json.files[i]);

         }

         setTimeout(function () { _this.PostFirst(); },500);

    };

    this.open_folders = function (json)

    {

        for (var i = 0, l = json.folders.length; i < l; ++i) {

            this.addFolderLoc(json.folders[i]);

        }

         setTimeout(function () { _this.PostFirst(); }, 500);

    };

    this.paste_files = function (json)

    {

         for (var i = 0, l = json.files.length; i < l; ++i)

         {

             this.addFileLoc(json.files[i]);

         }

    };

    后台在接收文件夹时不同之处在需要用MultipartHttpServletRequest

    boolean isMultipart = ServletFileUpload.isMultipartContent(request);

    FileItemFactory factory = new DiskFileItemFactory();  

    ServletFileUpload upload = new ServletFileUpload(factory);

    List files = null;

    try

    {

         files = upload.parseRequest(request);

    }

    catch (FileUploadException e)

    {// 解析文件数据错误 

        out.println("read file data error:" + e.toString());

        return;

      

    }

    FileItem rangeFile = null;

    // 得到所有上传的文件

    Iterator fileItr = files.iterator();

    // 循环处理所有文件

    while (fileItr.hasNext())

    {

         // 得到当前文件

         rangeFile = (FileItem) fileItr.next();

         if(StringUtils.equals( rangeFile.getFieldName(),"pathSvr"))

         {

             pathSvr = rangeFile.getString();

             pathSvr = PathTool.url_decode(pathSvr);

         }

    }

    server端的包和类

    文件块处页面,验证代码部分

    boolean verify = false;

    String msg = "";

    String md5Svr = "";

    long blockSizeSvr = rangeFile.getSize();

    if(!StringUtils.isBlank(blockMd5))

    {

         md5Svr = Md5Tool.fileToMD5(rangeFile.getInputStream());

    }

    verify = Integer.parseInt(blockSize) == blockSizeSvr;

    if(!verify)

    {

         msg = "block size error sizeSvr:" + blockSizeSvr + "sizeLoc:" + blockSize;

    }

    if(verify && !StringUtils.isBlank(blockMd5))

    {

         verify = md5Svr.equals(blockMd5);

         if(!verify) msg = "block md5 error";

    }

    if(verify)

    {

         //保存文件块数据

         FileBlockWriter res = new FileBlockWriter();

         //仅第一块创建

         if( Integer.parseInt(blockIndex)==1) res.CreateFile(pathSvr,Long.parseLong(lenLoc));

         res.write( Long.parseLong(blockOffset),pathSvr,rangeFile);

         up6_biz_event.file_post_block(id,Integer.parseInt(blockIndex));

        

         JSONObject o = new JSONObject();

         o.put("msg", "ok");

         o.put("md5", md5Svr); 

         o.put("offset", blockOffset);//基于文件的块偏移位置

         msg = o.toString();

    }

    rangeFile.delete();

    out.write(msg);

    生成文件名称的逻辑

    public String genFile(int uid, String md5,String nameLoc) throws IOException

    {

         SimpleDateFormat fmtDD = new SimpleDateFormat("dd");

         SimpleDateFormat fmtMM = new SimpleDateFormat("MM");

         SimpleDateFormat fmtYY = new SimpleDateFormat("yyyy");

        

         Date date = new Date();

         String strDD = fmtDD.format(date);

         String strMM = fmtMM.format(date);

         String strYY = fmtYY.format(date);

        

         String path = this.getRoot() + "/";

         path = path.concat(strYY);

         path = path.concat("/");

         path = path.concat(strMM);

         path = path.concat("/");

         path = path.concat(strDD);

         path = path.concat("/");

         path = path.concat(md5);

         path = path.concat(".");

         path = path.concat(PathTool.getExtention(nameLoc));

            

        

         File fl = new File(path);

        

         return fl.getCanonicalPath();//

    }

    以下是service层做的处理:

    整体模块划分如下:

    其中数据类实体逻辑处理如下

    public class FileInf {

         public FileInf(){}

         public String id="";

         public String pid="";

        public String pidRoot="";   

         /**  * 表示当前项是否是一个文件夹项。    */

         public boolean fdTask=false;        

         //   /// 是否是文件夹中的子文件  ///

         public boolean fdChild=false;

         /**  * 用户ID。与第三方系统整合使用。    */

         public int uid=0;

         /**  * 文件在本地电脑中的名称   */

         public String nameLoc="";

         /**  * 文件在服务器中的名称。   */

         public String nameSvr="";

         /**  * 文件在本地电脑中的完整路径。示例:D:SoftQQ2012.exe */

         public String pathLoc="";  

         /**  * 文件在服务器中的完整路径。示例:F:\ftp\uer\md5.exe     */

         public String pathSvr="";

         /**  * 文件在服务器中的相对路径。示例:/www/web/upload/md5.exe   */

         public String pathRel="";

         /**  * 文件MD5    */

         public String md5="";

         /**  * 数字化的文件长度。以字节为单位,示例:120125    */

         public long lenLoc=0;

         /**  * 格式化的文件尺寸。示例:10.03MB   */

         public String sizeLoc="";

         /**  * 文件续传位置。  */

         public long offset=0;

         /**  * 已上传大小。以字节为单位 */

         public long lenSvr=0;

         /**  * 已上传百分比。示例:10%  */

         public String perSvr="0%";

         public boolean complete=false;

         public Date PostedTime = new Date();

         public boolean deleted=false;

         /**  * 是否已经扫描完毕,提供给大型文件夹使用,大型文件夹上传完毕后开始扫描。  */

         public boolean scaned=false;

    }

    后台数据库中的逻辑基本上都用到了上面的实体类

    文件数据表操作类如下

    加载所有未完成的文件列表

    public String GetAllUnComplete(int f_uid)

    {

         StringBuilder sb = new StringBuilder();

         sb.append("select ");

         sb.append(" f_id");

         sb.append(",f_fdTask");    

         sb.append(",f_nameLoc");

         sb.append(",f_pathLoc");

         sb.append(",f_md5");

         sb.append(",f_lenLoc");

         sb.append(",f_sizeLoc");

         sb.append(",f_pos");

         sb.append(",f_lenSvr");

         sb.append(",f_perSvr");

         sb.append(",f_complete");

         sb.append(",f_pathSvr");//fix(2015-03-16):修复无法续传文件的问题。

         sb.append(" from up6_files ");//change(2015-03-18):联合查询文件夹数据

         sb.append(" where f_uid=? and f_deleted=0 and f_fdChild=0 and f_complete=0 and f_scan=0");//fix(2015-03-18):只加载未完成列表

         ArrayList files = new ArrayList();

         DbHelper db = new DbHelper();

         PreparedStatement cmd = db.GetCommand(sb.toString());

         try {

             cmd.setInt(1, f_uid);

             ResultSet r = db.ExecuteDataSet(cmd);

             while(r.next())

             {

                  FileInf f          = new FileInf();

                  f.uid              = f_uid;

                  f.id               = r.getString(1);

                  f.fdTask      = r.getBoolean(2);              

                  f.nameLoc          = r.getString(3);

                  f.pathLoc          = r.getString(4);

                  f.md5              = r.getString(5);

                  f.lenLoc      = r.getLong(6);

                  f.sizeLoc          = r.getString(7);

                  f.offset      = r.getLong(8);

                  f.lenSvr      = r.getLong(9);

                  f.perSvr      = r.getString(10);

                  f.complete         = r.getBoolean(11);

                  f.pathSvr     = r.getString(12);//fix(2015-03-19):修复无法续传文件的问题。

                  files.add(f);

                 

             }

             r.close();

             cmd.getConnection().close();

             cmd.close();

         } catch (SQLException e) {

             // TODO Auto-generated catch block

             e.printStackTrace();

         }

        

         if(files.size() < 1) return null;

        

         Gson g = new Gson();

        return g.toJson( files);//bug:arrFiles为空时,此行代码有异常

    }

    实现后的整体效果如下

    文件夹上传完后的效果

    服务器保存的文件夹数据,而且层级结构与本地客户端是一致的。这在OA系统中,或者网盘系统中使用时是非常有用的

    后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/java-http%E5%A4%A7%E6%96%87%E4%BB%B6%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0%E4%B8%8A%E4%BC%A0/

    欢迎入群一起讨论“374992201”

  • 相关阅读:
    那些年,加班搞过的需求...
    在基于nuxt的移动端页面中引用mint UI的popup组件之父子组件传值
    nuxt下运行项目时内存溢出(out of memory)的一种情况
    转载的
    VUE旅程(2)
    用windbg+sos找出程序中谁占用内存过高,谁占用CPU过高(转载)
    分块算法总结(持续更新ing)
    【MATLAB建模学习实录【三】】插值与拟合、数据处理
    【MATLAB建模学习实录【二】】非线性规划函数模型板子
    【MATLAB建模学习实录【一】】MATLAB求解线性规划模板
  • 原文地址:https://www.cnblogs.com/songsu/p/14927450.html
Copyright © 2011-2022 走看看