JAVA上传大文件的三种解决方案

article/2025/9/30 2:04:38

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

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

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

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

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

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

<input id="fileFolder" name="fileFolder" type="file"  webkitdirectory>

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

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

前台HTML模板

this.GetHtmlFiles = function()

{

     var acx = "";

     acx += '<div class="file-item" id="tmpFile" name="fileItem">\

                <div class="img-box"><img name="file" src="js/file.png"/></div>\

                   <div class="area-l">\

                       <div class="file-head">\

                            <div name="fileName" class="name">HttpUploader程序开发.pdf</div>\

                            <div name="percent" class="percent">(35%)</div>\

                            <div name="fileSize" class="size" child="1">1000.23MB</div>\

                    </div>\

                       <div class="process-border"><div name="process" class="process"></div></div>\

                       <div name="msg" class="msg top-space">15.3MB 20KB/S 10:02:00</div>\

                   </div>\

                   <div class="area-r">\

                    <span class="btn-box" name="cancel" title="取消"><img name="stop" src="js/stop.png"/><div>取消</div></span>\

                    <span class="btn-box hide" name="post" title="继续"><img name="post" src="js/post.png"/><div>继续</div></span>\

                       <span class="btn-box hide" name="stop" title="停止"><img name="stop" src="js/stop.png"/><div>停止</div></span>\

                       <span class="btn-box hide" name="del" title="删除"><img name="del" src="js/del.png"/><div>删除</div></span>\

                   </div>';

     acx += '</div>';

     //文件夹模板

     acx += '<div class="file-item" name="folderItem">\

                   <div class="img-box"><img name="folder" src="js/folder.png"/></div>\

                   <div class="area-l">\

                       <div class="file-head">\

                            <div name="fileName" class="name">HttpUploader程序开发.pdf</div>\

                            <div name="percent" class="percent">(35%)</div>\

                            <div name="fileSize" class="size" child="1">1000.23MB</div>\

                    </div>\

                       <div class="process-border top-space"><div name="process" class="process"></div></div>\

                       <div name="msg" class="msg top-space">15.3MB 20KB/S 10:02:00</div>\

                   </div>\

                   <div class="area-r">\

                    <span class="btn-box" name="cancel" title="取消"><img name="stop" src="js/stop.png"/><div>取消</div></span>\

                    <span class="btn-box hide" name="post" title="继续"><img name="post" src="js/post.png"/><div>继续</div></span>\

                       <span class="btn-box hide" name="stop" title="停止"><img name="stop" src="js/stop.png"/><div>停止</div></span>\

                       <span class="btn-box hide" name="del" title="删除"><img name="del" src="js/del.png"/><div>删除</div></span>\

                   </div>';

     acx += '</div>';

     //上传列表

     acx += '<div class="files-panel" name="post_panel">\

                   <div name="post_head" class="toolbar">\

                       <span class="btn" name="btnAddFiles">选择多个文件</span>\

                       <span class="btn" name="btnAddFolder">选择文件夹</span>\

                       <span class="btn" name="btnPasteFile">粘贴文件和目录</span>\

                       <span class="btn" name="btnSetup">安装控件</span>\

                   </div>\

                   <div class="content" name="post_content">\

                       <div name="post_body" class="file-post-view"></div>\

                   </div>\

                   <div class="footer" name="post_footer">\

                       <span class="btn-footer" name="btnClear">清除已完成文件</span>\

                   </div>\

              </div>';

     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;        

     //   /// 是否是文件夹中的子文件  /// </summary>

     public boolean fdChild=false;

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

     public int uid=0;

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

     public String nameLoc="";

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

     public String nameSvr="";

     /**  * 文件在本地电脑中的完整路径。示例:D:\Soft\QQ2012.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<FileInf> files = new ArrayList<FileInf>();

     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。在使用前需要配置一下数据库

控件源码下载:

asp.net源码下载,jsp-springboot源码下载,jsp-eclipse源码下载,jsp-myeclipse源码下载,php源码下载,csharp-winform源码下载,vue-cli源码下载,c++源码下载

详细配置信息及思路


http://chatgpt.dhexx.cn/article/gGoBqsJi.shtml

相关文章

大文件如何快速上传?

前言 大文件快速上传的方案&#xff0c;相信你也有过了解&#xff0c;其实无非就是将 文件变小&#xff0c;也就是通过 压缩文件资源或者 文件资源分块 后再上传。 本文只介绍资源分块上传的方式&#xff0c;并且会通过 前端&#xff08;vue3 vite&#xff09; 和 服务端&…

Java如何上传大文件

1 背景 用户本地有一份txt或者csv文件&#xff0c;无论是从业务数据库导出、还是其他途径获取&#xff0c;当需要使用蚂蚁的大数据分析工具进行数据加工、挖掘和共创应用的时候&#xff0c;首先要将本地文件上传至ODPS&#xff0c;普通的小文件通过浏览器上传至服务器&#xf…

Github上传大文件(>25MB)教程

Github上传大文件&#xff08;>25MB&#xff09;教程 Github上传大文件&#xff08;>25MB&#xff09;教程安装git安装Git Large File Storage实例踩坑点1&#xff1a;failed to push some refs to踩坑点2&#xff1a;main与master踩坑点3&#xff1a;Failed to connect …

如何高效的上传大文件?

业务场景&#xff1a;在很多业务中会涉及到文件上传&#xff0c;对于上传的文件大小要求也相对比较广&#xff0c;对于小文件而言我们使用MultipartFile上传就能解决&#xff0c;对于大文件来说可能也就将文件拆分成多份&#xff0c;一份一份的上传&#xff0c;大部分业务是足以…

请问:怎么实现大文件快速上传?

关注公众号 前端开发博客&#xff0c;领27本电子书 回复加群&#xff0c;自助秒进前端群 前言 大文件快速上传的方案&#xff0c;相信你也有过了解&#xff0c;其实无非就是将 文件变小&#xff0c;也就是通过 压缩文件资源 或者 文件资源分块 后再上传。 本文只介绍资源分块上…

超大文件上传解决方案

一、 功能性需求与非功能性需求 要求操作便利&#xff0c;一次选择多个文件和文件夹进行上传&#xff1b; 支持PC端全平台操作系统&#xff0c;Windows,Linux,Mac 支持文件和文件夹的批量下载&#xff0c;断点续传。刷新页面后继续传输。关闭浏览器后保留进度信息。 支持文件…

上传大文件(10G)的解决方案

需求&#xff1a; 项目要支持大文件上传功能&#xff0c;经过讨论&#xff0c;初步将文件上传大小控制在20G内&#xff0c;因此自己需要在项目中进行文件上传部分的调整和配置&#xff0c;自己将大小都以20G来进行限制。 PC端全平台支持&#xff0c;要求支持Windows,Mac,Linu…

linux操作系统实用教程课后答案,Linux操作系统案例教程课后习题答案

Linux操作系统案例教程课后习题答案 (3页) 本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01; 11.90 积分 &#xfeff;Linux操作系统案例教程课后习题答案第一章一 1.(D) 2.(B,C) 3.(A,B,D)4.(A,C,D ) …

第一章 Linux操作系统概述

接下来我将根据《Linux C编程完全解密》这本书&#xff0c;整理Linux系列相关笔记&#xff0c;并写成文章。本文将是该系列文章的第一篇。 第1章 Linux操作系统概述 1.1 认识Linux操作系统 1.1.1 Linux操作系统发展背景 Linux操作系统核心最早是由芬兰的Linus Torvalds于199…

SRE运维工程师笔记-安装linux系统(国产统信UOS操作系统)

SRE运维工程师笔记-安装linux系统&#xff08;国产统信UOS操作系统&#xff09; 1. 安装统信UOS系统1.1 针对统信UOS操作系统创建虚拟机环境1.2 安装国产统信UOS操作系统 1. 安装统信UOS系统 1.1 针对统信UOS操作系统创建虚拟机环境 简单介绍一下国产统信系统的安装&#xff…

Linux操作系统——定制自己的 Linux 系统

文章目录 22 定制自己的 Linux 系统22.1 基本介绍22.2 基本原理22.3 制作 min linux 思路分析22.4 操作步骤 22 定制自己的 Linux 系统 22.1 基本介绍 通过裁剪现有 Linux 系统(CentOS7.6)&#xff0c;创建属于自己的 min Linux 小系统&#xff0c;可以加深我们对 linux 的理…

linux系统下的基本操作

Linux 操作系统 1. Linux操作系统认知 1.1 操作系统&#xff08;Operation System简称OS&#xff09; 定义 操作系统是管理计算机硬件与软件资源的计算机程序&#xff0c;同时也是计算机系统的内核与基石。操作系统需要处理如管理与配置内存、决定系统资源供需的优先次序、控…

Linux 系统相关介绍

Linux 系统相关说明 Linux 内核版本 没有图形化页面 稳定版 : 面向普通用户 开发版 : 面向开发人员 Linux 发行版 在内核版本的基础上, 增加比如桌面/音乐播放器等应用软件的系统 (不同公司的发行版, 名称不同)

讲讲Linux系统工程师的职业规划

时至今日&#xff0c;Linux操作系统越来越成为主流的桌面操作系统&#xff0c;自从在一年前看到了编程大神王垠写的一篇文章——完全用Linux工作&#xff0c;我决定学习使用Linux操作系统。因Windows在服务器领域的份额越来越低&#xff0c;学习具有安全和高效等特点的Linux操作…

Linux系统编程之进程退出,父进程等待子进程退出

1.首先讲一下进程的退出 进程的退出分为正常退出和异常退出&#xff1a; 正常退出&#xff1a; (1)main函数调用return (2)进程调用exit()&#xff0c;标准C库 &#xff08;3&#xff09;进程调用_exit()或_Exit()&#xff0c;属于系统调用 &#xff08;4&#xff09;进程最后一…

linux开发工程师主要是干什么的?

转载自&#xff1a;http://emb.hqyj.com/linux/10328.html 作者&#xff1a;清华远见 在新手眼里&#xff0c;大多数都不知道linux开发工程师主要是干什么的。其实linux开发工程师的主要工作内容有很多&#xff0c;需要学习的知识点也挺多的。学习这些东西以后&#xff0c;就可…

Linux 下怎么查看服务器的cpu和内存的硬件信息

一、top命令 top # 实时显示进程状态用户 和 查看CPU利用率 二、查看总内存的方法&#xff1a; free命令主要用于显示内存数量&#xff0c;如下图中内容所表示 free -h 命令 free -m 命令

如何通过命令查看服务器的内存条使用情况

其实就一个命令就搞定了&#xff1a;dmidecode。 最常用的选项就是用 -t 或者 --type 来限定关键字&#xff1a; bios, system, baseboard, chassis, processor, memory, cache, connector, slot 关于这些关键字可以百度是什么意思&#xff0c; 或者去看man手册页&#xff0c;这…

Linux 查看服务器内存、CPU、网络等占用情况的命令--汇总

搭建测试环境过程中&#xff0c;需要对正在使用的aws服务器&#xff0c;查看它在运行脚本&#xff0c;启动脚本时的内存&#xff0c;CPU&#xff0c;网络等使用情况 1、查看物理CPU个数&#xff1a;cat cat /proc/cpuinfo | grep "physical id" | sort | uniq | w…