news 2026/8/11 11:32:03

经验交流:Java如何优化文件夹上传的内存占用与分片大小动态调整策略?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
经验交流:Java如何优化文件夹上传的内存占用与分片大小动态调整策略?

📌毕业设计求生指南:大文件上传系统(兼容IE8版)

😩 现状描述

大家好,我是浙江某三本计算机专业的大三学生,马上要毕业了,现在被导师逼着搞一个**「支持10G文件上传的系统」**,要求如下:

  1. 必须用原生JS(不能用jQuery等库)
  2. 支持IE8及国产浏览器(龙芯、红莲花、奇安信)
  3. 支持文件夹上传(保留层级结构)
  4. 断点续传(重启电脑也不能丢进度)
  5. 加密传输+存储(AES/SM4)
  6. 后端用SpringBoot(我Java还没学透)
  7. 前端用Vue3(但导师说IE8不支持,让我用原生JS)
  8. 对象存储用阿里云OSS(但学校服务器是本地CentOS虚拟机)

💢 最气的是:网上找的代码要么只能传5MB小文件,要么文件夹上传是残废的,最离谱的是作者连个联系方式都不留,出了问题只能对着屏幕喊**「爸爸救我」**……


💡 解决方案(抄作业版)

🖥️ 前端部分(原生JS + 兼容IE8)

1. 文件选择与文件夹上传(兼容IE8)

// FileUploader.js(兼容IE8的魔改版)functionFileUploader(containerId,config){this.config=Object.assign({chunkSize:5*1024*1024,// 5MB分片maxRetry:3,encrypt:true},config);// 检测浏览器类型(IE8特殊处理)this.isIE8=!!window.ActiveXObject&&!document.addEventListener;// 初始化UIthis.initUI(containerId);}FileUploader.prototype.initUI=function(containerId){constcontainer=document.getElementById(containerId);container.innerHTML=`开始上传`;// IE8用Flash模拟文件夹选择(伪代码)if(this.isIE8){this.setupIE8Fallback();}// 绑定事件document.getElementById('startBtn').addEventListener('click',()=>{constfiles=document.getElementById('fileInput').files;this.handleFiles(files);});};// 处理文件(支持文件夹层级)FileUploader.prototype.handleFiles=function(files){constfileTree={};// 遍历文件,构建层级结构for(leti=0;i<files.length;i++){constfile=files[i];constpath=this.isIE8?file.name:file.webkitRelativePath;constparts=path.split('/');letcurrent=fileTree;for(letj=0;j<parts.length-1;j++){constdir=parts[j];if(!current[dir]){current[dir]={};}current=current[dir];}current[parts[parts.length-1]]=file;}// 开始上传this.uploadFileTree(fileTree);};

2. 分片上传 + 断点续传(支持离线保存进度)

// 分片上传核心逻辑FileUploader.prototype.uploadFile=function(file,relativePath=''){constfileId=this.generateFileId(file);consttotalChunks=Math.ceil(file.size/this.config.chunkSize);letcurrentChunk=0;// 从本地存储加载进度constsavedProgress=this.loadProgress(fileId);if(savedProgress){currentChunk=savedProgress.currentChunk;}constuploadChunk=()=>{if(currentChunk>=totalChunks){this.onUploadComplete(fileId,relativePath);return;}conststart=currentChunk*this.config.chunkSize;constend=Math.min(start+this.config.chunkSize,file.size);constchunk=file.slice(start,end);// 加密处理(伪代码)letencryptedChunk=chunk;if(this.config.encrypt){encryptedChunk=this.encryptData(chunk);// 实际要用SM4/AES库}constformData=newFormData();formData.append('fileId',fileId);formData.append('chunkIndex',currentChunk);formData.append('totalChunks',totalChunks);formData.append('relativePath',relativePath);formData.append('file',newBlob([encryptedChunk]));// 发送请求(兼容IE8的XMLHttpRequest)constxhr=this.createXHR();xhr.open('POST','/api/upload',true);xhr.onload=()=>{if(xhr.status===200){currentChunk++;// 保存进度到localStoragethis.saveProgress(fileId,{currentChunk,totalChunks,fileName:file.name,relativePath});uploadChunk();}else{// 重试机制if(this.retryCount<this.config.maxRetry){this.retryCount++;setTimeout(uploadChunk,1000);}}};xhr.send(formData);};uploadChunk();};// 兼容IE8的XHR创建FileUploader.prototype.createXHR=function(){try{returnnewXMLHttpRequest();}catch(e){try{returnnewActiveXObject('Msxml2.XMLHTTP');}catch(e){returnnewActiveXObject('Microsoft.XMLHTTP');}}};

3. 断点续传持久化(localStorage + IE8降级方案)

// 保存上传进度FileUploader.prototype.saveProgress=function(fileId,progress){try{if(window.localStorage){localStorage.setItem(`upload_${fileId}`,JSON.stringify(progress));}else{// IE7及以下用userData存储(更古老的方案)this.saveToUserData(fileId,progress);}}catch(e){console.error('保存进度失败:',e);}};// 加载上传进度FileUploader.prototype.loadProgress=function(fileId){try{if(window.localStorage){constdata=localStorage.getItem(`upload_${fileId}`);returndata?JSON.parse(data):null;}// IE7及以下方案...}catch(e){console.error('加载进度失败:',e);returnnull;}};

🛠️ 后端部分(SpringBoot)

1. 文件分片接收控制器

@RestController@RequestMapping("/api/upload")publicclassFileUploadController{@Value("${oss.endpoint}")privateStringossEndpoint;@PostMappingpublicResponseEntityhandleFileUpload(@RequestParam("fileId")StringfileId,@RequestParam("chunkIndex")intchunkIndex,@RequestParam("totalChunks")inttotalChunks,@RequestParam("relativePath")StringrelativePath,@RequestParam("file")MultipartFilefile){try{// 1. 验证分片(防止恶意上传)if(chunkIndex<0||chunkIndex>=totalChunks){returnResponseEntity.badRequest().body("Invalid chunk index");}// 2. 保存到临时目录(实际项目用OSS)PathtempDir=Paths.get(System.getProperty("java.io.tmpdir"),"uploads",fileId);Files.createDirectories(tempDir);PathchunkPath=tempDir.resolve(chunkIndex+".part");Files.write(chunkPath,file.getBytes(),StandardOpenOption.CREATE);// 3. 如果是最后一个分片,合并文件if(chunkIndex==totalChunks-1){mergeFile(fileId,tempDir,totalChunks,relativePath);}returnResponseEntity.ok("Chunk uploaded successfully");}catch(Exceptione){returnResponseEntity.status(500).body("Upload failed: "+e.getMessage());}}privatevoidmergeFile(StringfileId,PathtempDir,inttotalChunks,StringrelativePath)throwsIOException{PathoutputPath=Paths.get(System.getProperty("java.io.tmpdir"),"uploads",fileId+".dat");try(OutputStreamout=Files.newOutputStream(outputPath,StandardOpenOption.CREATE)){for(inti=0;i<totalChunks;i++){PathchunkPath=tempDir.resolve(i+".part");Files.copy(chunkPath,out);Files.delete(chunkPath);// 清理分片}}// TODO: 上传到OSS并加密存储}}

2. 加密存储服务(SM4示例)

@ServicepublicclassCryptoService{// 使用BouncyCastle实现SM4(实际项目需要引入依赖)publicbyte[]encryptSM4(byte[]data,byte[]key)throwsException{SM4Engineengine=newSM4Engine();BufferedBlockCiphercipher=newPaddedBufferedBlockCipher(newCBCBlockCipher(engine));cipher.init(true,newParametersWithIV(newKeyParameter(key),newbyte[16]));byte[]output=newbyte[cipher.getOutputSize(data.length)];intbytesWritten=cipher.processBytes(data,0,data.length,output,0);bytesWritten+=cipher.doFinal(output,bytesWritten);returnArrays.copyOf(output,bytesWritten);}}

🎯 生存指南

  1. IE8兼容性

    • 用Flash作为降级方案(虽然很古老但有效)
    • 避免使用ES6+语法(用Babel转译)
    • 测试用Windows 7 + IE9虚拟机(学校机房同款)
  2. 大文件上传技巧

    • 分片大小控制在5-10MB
    • 使用Web Worker处理加密(避免UI卡顿)
    • 服务器端验证分片完整性
  3. 找工作秘籍

    • 把毕业设计包装成「企业级文件传输系统」
    • 重点强调「兼容信创环境」(国企/银行很吃这套)
    • 在GitHub挂个Demo(记得把测试账号密码写进README)

📢 最后吐槽:求各位大佬加群374992201啊!送红包是假的,但找工作互助是真的!群里还有大佬在阿里云/华为上班,说不定能内推呢~(群文件有完整项目代码和SQL脚本)


🚀 完整代码获取方式

  1. 加QQ群:374992201(送1~99元红包)
  2. GitHub:https://github.com/your-repo/file-uploader(待补充)
  3. 直接联系作者:QQ/微信在群公告

🙏 跪求大佬指导!毕业答辩就靠这个了!

导入项目

导入到Eclipse:点击查看教程
导入到IDEA:点击查看教程
springboot统一配置:点击查看教程

工程

NOSQL

NOSQL示例不需要任何配置,可以直接访问测试

创建数据表

选择对应的数据表脚本,这里以SQL为例

修改数据库连接信息

访问页面进行测试

文件存储路径

up6/upload/年/月/日/guid/filename

效果预览

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。

下载示例

点击下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 15:38:54

MATLAB仿真:双星TDOA/FDOA无源定位方法及其GDOP对比

【13】MATLAB仿真 双星TDOA/FDOA无源定位方法仿真&#xff0c;包含GDOP对比&#xff0c;有参考文档。 主要参考文档&#xff1a; 1.双星TDOA/FDOA无源定位方法分析&#xff0c;航天电子对抗 2. 双星时差频差联合定位方法及其误差分析&#xff0c;宇航学报 3. Geolocation of a…

作者头像 李华
网站建设 2026/7/21 13:50:57

拒绝加班!这套一键生成建筑模型的方法,让甲方当场傻眼

一、概述 在智慧城市建设、城市规划设计、游戏场景搭建以及数字孪生应用等领域&#xff0c;三维建筑模型的构建始终是基础且关键的一环。传统建模方式依赖人工描图、手动拉伸&#xff0c;不仅耗时耗力&#xff0c;而且难以保证数据的现势性与准确性。尤其是面对大范围城市级别…

作者头像 李华
网站建设 2026/7/14 15:38:53

LP3783A芯茂微5V2.1A低功耗原边反馈充电器芯片替代PL3378/C

LP3783A是一款高性价比原边反馈&#xff08;PSR&#xff09;控制芯片&#xff0c;专为5V/2.1A&#xff08;10.5W&#xff09;充电器及适配器设计。该芯片内置850V高耐压功率三极管&#xff0c;采用SOP-7封装&#xff0c;支持恒压&#xff08;CV&#xff09;恒流&#xff08;CC&…

作者头像 李华
网站建设 2026/7/14 15:38:55

今日主题:Java 垃圾回收机制与主流回收器实战

今日主题&#xff1a;Java 垃圾回收机制与主流回收器实战 分代收集理论 JVM 基于“弱分代假说”&#xff08;绝大多数对象朝生夕死&#xff09;将堆划分为新生代&#xff08;Eden、Survivor0/1&#xff09;和老年代。新对象诞生于 Eden&#xff0c;熬过 Minor GC 则移入 Surviv…

作者头像 李华
网站建设 2026/7/14 15:38:52

解锁社区资源:如何发现和安装高质量的OpenClaw技能包

引言&#xff1a;站在巨人的肩膀上 OpenClaw的核心能力已经相当强大&#xff0c;但真正让它成为"超级工具"的是其技能包&#xff08;Skills&#xff09;生态系统。技能包就像是OpenClaw的"超能力扩展包"&#xff0c;让AI能够胜任特定领域的工作。 想象一…

作者头像 李华
网站建设 2026/7/14 15:38:55

哪些产品需要沙特SABER认证?一文说清

哪些产品需要沙特SABER认证&#xff1f;一文说清&#xff08;2026最新版&#xff09; 沙特SABER认证是沙特标准、计量和质量组织&#xff08;SASO&#xff09;推出的强制性产品合规认证系统&#xff0c;所有出口至沙特的管制类产品和非管制类产品均需通过该平台完成清关手续。…

作者头像 李华