大文件分片上传

article/2025/8/18 20:30:00

前言

前端进行文件大小分割  ,按10M分割进行分片上传,使用的项目还是前面文档介绍的poi同一个项目

另一篇poi导出文章,使用的同一个项目

poi的使用和工具类(一)

 开发

1、maven依赖

<!--文件分片上传使用到依赖 start  -->
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version>
</dependency>
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>16.0.1</version>
</dependency>
<dependency><groupId>com.twmacinta</groupId><artifactId>fast-md5</artifactId><version>2.7.1</version>
</dependency><!--文件分片上传使用到依赖 end  -->

配置文件

server:port: 9001#  rootdir文件上传根路径  linux:/xxx/xx/ window D:\Download\
#  tempdir: 分片临时目录
#  isDelTempFile   和片后是否删除临时目录
spring:uploader:rootdir: D:\Download\tempdir: tempisDelTempFile: true

 controller

package com.shan.controller;import com.shan.service.UploaderService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;/*** 分片上传* 思想* 1. 先 checkUpload()  文件上传前校验 根据自己公司需求校验*2. checkChunk()  检测指定分片是否存在   否 走uploadChunk()分片上传方法  是走merge()合成分片* 3. 分片上传时,会生成临时文件  必成分片是会把临时文件合成上传的真正文件,并删除临时文件**/
@RestController
@RequestMapping("uploader")
public class TestUploader {@Autowiredprivate UploaderService uploaderService;/*** 文件上传前校验** @param fileName 文件名称* @param size     文件大小 byte字节长度* @return*/@PostMapping("/checkUpload")public String checkUpload(String fileName, String size) {//根据公司自己业务  做校验   如文件名是否喊特殊字符 是否为空 等return "SUCCESS";}/*** 检查指定分片是否存在** @param md5Value    文件MD5值* @param chunk       第几片* @param moduleName  上传文件所在模块名称* @param fileTypeKey 文件类别   公司自己业务需求  会根据 模块名称+文件类别  定义上传目录* @return*/@PostMapping("/checkChunk")public Boolean checkChunk(String md5Value, Integer chunk, String moduleName, String fileTypeKey) {Boolean bool = uploaderService.checkChunk(md5Value, chunk, moduleName, fileTypeKey);return bool;}/*** 分片上传** @param file        文件对象* @param md5Value    文件MD5值* @param chunk       第几片* @param moduleName  上传文件所在模块名称* @param fileTypeKey 文件类别* @return*/@PostMapping("/uploadChunk")public String uploadChunk(MultipartFile file, String md5Value, Integer chunk, String moduleName, String fileTypeKey) {System.out.println("------------开始上传:" + file.getOriginalFilename());Boolean bool = uploaderService.uploadChunk(file, md5Value, chunk, moduleName, fileTypeKey);if (!bool) {return "FAILRE";}return "SUCCESS";}/*** 合成分片** @param chunkCount  总片数* @param md5Value    文件MD5值* @param fileName    文件名称* @param moduleName  上传文件所在模块名称* @param fileTypeKey 文件类别* @return*/@PostMapping("/merge")public String merge(Integer chunkCount, String md5Value, String fileName, String moduleName, String fileTypeKey) {String fileId = uploaderService.merge(chunkCount, md5Value, fileName, moduleName, fileTypeKey);if (StringUtils.isBlank(fileId)) {return "FAILRE";}return "SUCCESS";}}

service

package com.shan.service;import org.springframework.web.multipart.MultipartFile;public interface UploaderService {Boolean checkChunk(String md5Value, Integer chunk, String moduleName, String fileTypeKey);Boolean uploadChunk(MultipartFile file, String md5Value, Integer chunk, String moduleName, String fileTypeKey);String merge(Integer chunkCount, String md5Value, String fileName, String moduleName, String fileTypeKey);String specifiedDirectory(String fileTypeKey);}
package com.shan.service.impl;import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.shan.entity.po.CloudFile;
import com.shan.file.ResumeUploader;
import com.shan.service.UploaderService;
import com.shan.utils.ConstantUtils;
import com.shan.utils.Md5Util;
import com.shan.utils.UUIDGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.util.Date;
import java.util.Map;@Service
public class UploaderServiceImpl implements UploaderService {@Value("${spring.uploader.rootdir}")private String fileUploadPath;@Autowiredprivate  ResumeUploader fileOperation;@Overridepublic Boolean checkChunk(String md5Value, Integer chunk, String moduleName, String fileTypeKey) {String path = specifiedDirectory(fileTypeKey) + moduleName + File.separator + fileTypeKey + File.separator;return fileOperation.checkChunk(path, md5Value, chunk);}@Overridepublic Boolean uploadChunk(MultipartFile file, String md5Value, Integer chunk, String moduleName, String fileTypeKey) {String path = specifiedDirectory(fileTypeKey) + moduleName + File.separator + fileTypeKey + File.separator;return fileOperation.upload(file, path, md5Value, chunk);}@Overridepublic String merge(Integer chunkCount, String md5Value, String fileName, String moduleName, String fileTypeKey) {String path = specifiedDirectory(fileTypeKey) + moduleName + File.separator + fileTypeKey + File.separator;// 目录下如果存在相同名称的文件,对文件名称做修改   xxx(1).txt  xxx(2).txtfileName = this.verifyRepeatFile(path, fileName, 0);Boolean merge = fileOperation.merge(path, path, md5Value, chunkCount, fileName);if (merge) {String filePath = path + fileName;CloudFile cloudFile = new CloudFile();cloudFile.setId(UUIDGenerator.getUUID());cloudFile.setMd5(Md5Util.fastMD5(new File(filePath)));cloudFile.setName(fileName.substring(0, fileName.lastIndexOf(".")));cloudFile.setType(fileName.substring(fileName.lastIndexOf(".")));cloudFile.setPath(filePath);cloudFile.setFileSize(new File(filePath).length());cloudFile.setGmtCreate(new Date());//存数据库// int save = cloudFileMapper.save(cloudFile);int save =1;if (save > 0) {return cloudFile.getId();}}return null;}/*** 根据文件类型指定文件目录** @param fileTypeKey 文件类型*/@Overridepublic String specifiedDirectory(String fileTypeKey) {// 一、通用管理文件根路径String fPath = fileUploadPath;return fPath.endsWith("/") ? fPath : fPath + "/";}private String verifyRepeatFile(String path, String fileName, int i) {String name = fileName.substring(0, fileName.lastIndexOf("."));String suffix = fileName.substring(fileName.lastIndexOf("."));String tempFileName;if (i != 0) {tempFileName = String.format("%s%s%d%s", name, "(", i, ")");} else {tempFileName = name;}File file = new File(path + tempFileName + suffix);if (file.exists()) {return verifyRepeatFile(path, name + suffix, ++i);}return tempFileName + suffix;}}

 工具类 上传相关封装

ResumeUploader、CommonUploader、UploaderUtils 、UploaderUtils
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package com.shan.file;import java.io.InputStream;
import java.util.List;import com.shan.entity.bean.FileInfo;
import org.springframework.web.multipart.MultipartFile;public interface ResumeUploader {Boolean checkChunk(String var1, String var2, Integer var3);Boolean compress(List<String> var1, String var2);Boolean copy(String var1, String var2);Boolean delete(String var1);InputStream download(String var1);Boolean exists(String var1);Long getDiskSize(String var1);List<FileInfo> listFiles(String var1, boolean var2);Boolean merge(String var1, String var2, String var3, Integer var4, String var5);Boolean mkDir(String var1);Boolean move(String var1, String var2);Boolean rename(String var1, String var2);Boolean upload(MultipartFile var1, String var2, String var3, Integer var4);
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package com.shan.file;import com.google.common.collect.Lists;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;import com.shan.entity.bean.FileInfo;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@Component
public class CommonUploader implements ResumeUploader {@Value("${spring.uploader.tempdir}")private String tempDir;@Value("${spring.uploader.isDelTempFile}")private Boolean isDelTempFile;public Boolean checkChunk(String sharePath, String md5File, Integer chunk) {Boolean isExisted = false;String filePath = String.format("%s/%s/%s/%s.tmp", sharePath, this.tempDir, md5File, chunk);File file = new File(filePath);if (file.exists()) {isExisted = true;}return isExisted;}public Boolean compress(List<String> inputFilename, String zipFilename) {Boolean result = false;try {this.mkDir(zipFilename.substring(0, zipFilename.lastIndexOf("/") + 1));ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFilename));try {String item;String base;for(Iterator var5 = inputFilename.iterator(); var5.hasNext(); this.zip(out, item, base)) {item = (String)var5.next();base = "";String[] items = item.split("/");if (item.lastIndexOf("/") + 1 == item.length()) {base = items[items.length - 1] + "/";} else {base = items[items.length - 1];}}result = true;} catch (Throwable var10) {try {out.close();} catch (Throwable var9) {var10.addSuppressed(var9);}throw var10;}out.close();} catch (Exception var11) {var11.printStackTrace();result = false;}return result;}public Boolean copy(String fromPath, String tofilePath) {Boolean result = false;try {File fromFile = new File(fromPath);File toFile = new File(tofilePath);if (fromFile.exists()) {if (fromFile.isDirectory()) {FileUtils.copyDirectory(fromFile, toFile);} else {FileUtils.copyFile(fromFile, toFile);}result = toFile.exists();}} catch (Exception var6) {var6.printStackTrace();result = false;}return result;}public Boolean delete(String path) {Boolean result = false;try {File remoteFile = new File(path);if (!remoteFile.exists()) {return false;}if (remoteFile.isFile()) {result = remoteFile.delete();} else {FileUtils.deleteDirectory(remoteFile);result = true;}} catch (Exception var4) {var4.printStackTrace();result = false;}return result;}public InputStream download(String fromPath) {FileInputStream inputStream = null;try {File file = new File(fromPath);if (file.exists()) {inputStream = new FileInputStream(file);}} catch (Exception var4) {var4.printStackTrace();}return inputStream;}public Boolean exists(String path) {return (new File(path)).exists();}public Long getDiskSize(String path) {return this.getDiskSizeByte(path) / 1024L;}private Long getDiskSizeByte(String path) {long result = 0L;try {File file = new File(path);if (file.isFile()) {result += file.length();} else {File[] files = file.listFiles();File[] var6 = files;int var7 = files.length;for(int var8 = 0; var8 < var7; ++var8) {File f = var6[var8];if (f.isFile()) {result += f.length();}if (f.isDirectory()) {result += this.getDiskSizeByte(f.getPath().substring(f.getPath().indexOf("@") + 1));}}}} catch (Exception var10) {var10.printStackTrace();return 0L;}return result;}public List<FileInfo> listFiles(String path, boolean calculateFolderSize) {ArrayList result = Lists.newArrayList();try {File file = new File(path);if (file.exists() && file.isDirectory()) {File[] files = file.listFiles();File[] var6 = files;int var7 = files.length;for(int var8 = 0; var8 < var7; ++var8) {File f = var6[var8];Boolean isFile = f.isFile();String filePath = f.getPath();String fileName = isFile ? f.getName() : "";Long size = 0L;if (isFile) {size = f.length() / 1024L;} else if (calculateFolderSize) {size = this.getDiskSize(filePath.substring(filePath.indexOf("@") + 1));}result.add(new FileInfo(f.getName(), isFile, f.getPath(), fileName.substring(fileName.lastIndexOf(".") + 1), size));}}} catch (Exception var14) {var14.printStackTrace();}return result;}public Boolean merge(String uploadPath, String temPath, String md5File, Integer chunks, String name) {Boolean result = false;this.mkDir(uploadPath);this.mkDir(temPath);try {FileOutputStream fileOutputStream = new FileOutputStream(String.format("%s/%s", uploadPath, name));try {byte[] buf = new byte[104857600];long i = 0L;while(true) {if (i >= (long)chunks) {if (this.isDelTempFile) {this.delete(String.format("%s/%s/%s/", temPath, this.tempDir, md5File));}result = true;break;}File file = new File(String.format("%s/%s/%s/%s.tmp", temPath, this.tempDir, md5File, i));FileInputStream inputStream = new FileInputStream(file);try {boolean var13 = false;int len;while((len = inputStream.read(buf)) != -1) {fileOutputStream.write(buf, 0, len);}} catch (Throwable var17) {try {inputStream.close();} catch (Throwable var16) {var17.addSuppressed(var16);}throw var17;}inputStream.close();++i;}} catch (Throwable var18) {try {fileOutputStream.close();} catch (Throwable var15) {var18.addSuppressed(var15);}throw var18;}fileOutputStream.close();} catch (Exception var19) {result = false;}return result;}public Boolean mkDir(String path) {Boolean result = false;try {File file = new File(path);if (!file.exists()) {result = file.mkdirs();}} catch (Exception var4) {var4.printStackTrace();result = false;}return result;}public Boolean move(String fromPath, String toPath) {Boolean result = false;try {Boolean isCopy = this.copy(fromPath, toPath);Boolean isDel = false;if (isCopy) {isDel = this.delete(fromPath);}result = isCopy && isDel;} catch (Exception var6) {var6.printStackTrace();result = false;}return result;}public Boolean rename(String oldName, String newName) {Boolean result = false;try {File oldFile = new File(oldName);File newFile = new File(newName);oldFile.renameTo(newFile);result = newFile.exists();} catch (Exception var6) {var6.printStackTrace();result = false;}return result;}public Boolean upload(MultipartFile file, String sharePath, String md5File, Integer chunk) {try {String path = String.format("%s/%s/%s/", sharePath, this.tempDir, md5File);FileUtils.forceMkdir(new File(path));String chunkName = chunk == null ? "0.tmp" : chunk.toString().concat(".tmp");File savefile = new File(path.concat(chunkName));if (!savefile.exists()) {savefile.createNewFile();}file.transferTo(savefile);} catch (IOException var8) {return false;}return true;}private void zip(ZipOutputStream out, String inputFilename, String base) throws Exception {File file = new File(inputFilename);if (file.exists()) {if (file.isDirectory()) {File[] files = file.listFiles();base = base.length() == 0 ? "" : base;for(int i = 0; i < files.length; ++i) {String filePath = files[i].getPath();this.zip(out, filePath.substring(filePath.indexOf("@") + 1), base + files[i].getName());}} else {out.putNextEntry(new ZipEntry(base));int len = 0;byte[] buf = new byte[104857600];FileInputStream inputStream = new FileInputStream(file);try {while((len = inputStream.read(buf)) != -1) {out.write(buf, 0, len);}} catch (Throwable var11) {try {inputStream.close();} catch (Throwable var10) {var11.addSuppressed(var10);}throw var11;}inputStream.close();}}}public String getTempDir() {return this.tempDir;}public Boolean getIsDelTempFile() {return this.isDelTempFile;}public void setTempDir(String tempDir) {this.tempDir = tempDir;}public void setIsDelTempFile(Boolean isDelTempFile) {this.isDelTempFile = isDelTempFile;}public boolean equals(Object o) {if (o == this) {return true;} else if (!(o instanceof CommonUploader)) {return false;} else {CommonUploader other = (CommonUploader)o;if (!other.canEqual(this)) {return false;} else {Object this$isDelTempFile = this.getIsDelTempFile();Object other$isDelTempFile = other.getIsDelTempFile();if (this$isDelTempFile == null) {if (other$isDelTempFile != null) {return false;}} else if (!this$isDelTempFile.equals(other$isDelTempFile)) {return false;}Object this$tempDir = this.getTempDir();Object other$tempDir = other.getTempDir();if (this$tempDir == null) {if (other$tempDir != null) {return false;}} else if (!this$tempDir.equals(other$tempDir)) {return false;}return true;}}}protected boolean canEqual(Object other) {return other instanceof CommonUploader;}public int hashCode() {int PRIME =  59;int result = 1;Object $isDelTempFile = this.getIsDelTempFile();result = result * 59 + ($isDelTempFile == null ? 43 : $isDelTempFile.hashCode());Object $tempDir = this.getTempDir();result = result * 59 + ($tempDir == null ? 43 : $tempDir.hashCode());return result;}public String toString() {return "CommonUploader(tempDir=" + this.getTempDir() + ", isDelTempFile=" + this.getIsDelTempFile() + ")";}public CommonUploader() {}public CommonUploader(String tempDir, Boolean isDelTempFile) {this.tempDir = tempDir;this.isDelTempFile = isDelTempFile;}
}
package com.shan.utils;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public class Md5Util {private static final char[] hexCode = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};public static String calcMD5(File file) {try (InputStream stream = Files.newInputStream(file.toPath(), StandardOpenOption.READ)) {MessageDigest digest = MessageDigest.getInstance("MD5");byte[] buf = new byte[8192];int len;while ((len = stream.read(buf)) > 0) {digest.update(buf, 0, len);}return toHexString(digest.digest());} catch (IOException | NoSuchAlgorithmException e) {e.printStackTrace();return "";}}private static String toHexString(byte[] data) {StringBuilder r = new StringBuilder(data.length * 2);for (byte b : data) {r.append(hexCode[(b >> 4) & 0xF]);r.append(hexCode[(b & 0xF)]);}return r.toString().toLowerCase();}public static String calcMd5(String s) {if (s == null || "".equals(s)) {return "";}try {byte[] strTemp = s.getBytes();MessageDigest mdTemp = MessageDigest.getInstance("MD5");mdTemp.update(strTemp);byte[] md = mdTemp.digest();int j = md.length;char[] str = new char[j * 2];int k = 0;for (byte byte0 : md) {str[k++] = hexCode[byte0 >>> 4 & 0xf];str[k++] = hexCode[byte0 & 0xf];}return new String(str);} catch (Exception e) {e.printStackTrace();return "";}}/*** Fast MD5 PLUS*/public static String fastMD5(File file) {int len = 10000;try {if(file.length() < 10000000){return com.twmacinta.util.MD5.asHex(com.twmacinta.util.MD5.getHash(file));}byte pond[] =new byte [len];RandomAccessFile raf = new RandomAccessFile(file, "r");raf.seek(file.length() - len);raf.read(pond, 0, len);return calcMd5(toHexString(pond));} catch (Exception e) {e.printStackTrace();return "";}}public static void main(String[] args) {File file = new File("D:\\软件\\360极速浏览器.zip");String s = Md5Util.fastMD5(file);System.out.println(s);}}

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package com.shan.utils;import java.io.File;
import java.io.IOException;
import java.util.Date;import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;public class UploaderUtils {private static final Logger logger = LoggerFactory.getLogger(UploaderUtils.class);public UploaderUtils() {}public static String uploadFile(MultipartFile file, String filePath) {String fileName = file.getOriginalFilename();String newFileName = DateUtils.getInstance().dateFormat(new Date(System.currentTimeMillis()));String ext = "";if (!StringUtils.isEmpty(fileName)) {ext = fileName.substring(fileName.lastIndexOf("."), fileName.length());}//目标路径+当时时间 yyyy-MM-ddString targetFilePath = filePath + File.separator + DateUtils.getInstance().dateFormat10(System.currentTimeMillis());logger.info("上传路径{}", targetFilePath);System.out.println();File targetFile = new File(targetFilePath, newFileName + ext);if (!targetFile.getParentFile().exists()) {targetFile.getParentFile().mkdirs();}try {file.transferTo(targetFile);} catch (IllegalStateException var7) {var7.printStackTrace();} catch (IOException var8) {var8.printStackTrace();}return targetFile.getPath();}
}

前端代码 先不放了  因公司保密性  参数放上了可以直接调用

测试

1、检查分片是否存在 

chunk   0

md5Value  e80c5740b90c9366d0ab0b271f8a10c8

moduleName

fileTypeKey   3D/DCV/v1

 2、上传分片

file   选择文件

chunk   0

md5Value  e80c5740b90c9366d0ab0b271f8a10c8

moduleName

fileTypeKey   3D/DCV/v1

上传后看上传的位置   会生成分片文件

 3、合并分片

fileName  test2.xls

chunkCount   1

md5Value  e80c5740b90c9366d0ab0b271f8a10c8

moduleName

fileTypeKey   3D/DCV/v1

合并分片后会删除 临时分片文件  并生成原文件

文件夹上传

前台分为点击上传文件夹和拖拽文件夹

思路:

  * 文件夹上传 前台分为点击上传文件夹和拖拽上传文件夹
     *  1. 对文件夹中的文件循环校验  /uploader/beforeUpload方法
     *  2. 上传文件夹    /uploader/uploadFolder方法

 /*** 文件夹上传 前台分为点击上传文件夹和拖拽上传文件夹*  1. 对文件夹中的文件循环校验  /uploader/beforeUpload方法*  2. 上传文件夹    /uploader/uploadFolder方法* @param request*  fileId = 在非第一级上传文件时,fileId有值-为所在文件夹的id,上传的路径为  云盘的根路径+上文件的路径*  file 上传的文件夹 多个文件*  names 前台分为点击上传文件夹和拖拽上传文件夹*          点击上传文件夹时,文件的名称中不包含层级关系*          拖拽上传文件夹,文件的名称中包含层级关系,names参数为拖拽上传时使用,里面包含所有文件的层级关系*          如 names: /360驱动大师目录/下载保存目录/audio_conexant_8.66.83.51_w1064.zip.mem,/360驱动大师目录/下载保存目录/audio_conexant_8.66.83.51_w1064.zip.trt* @return*/@PostMapping("uploadFolder")public Boolean uploadFolder(HttpServletRequest request) {try {MultipartHttpServletRequest params = ((MultipartHttpServletRequest) request);// 在非第一级上传文件时,fileId有值-为所在文件夹的id,上传的路径为  根路径+上文件的路径String fileId = params.getParameter("fileId");fileId = StringUtils.isBlank(fileId) ? "0" : fileId;String filePath = "0".equals(fileId) ? "" : uploaderService.getFilePathByFileId(fileId);String targetDirectoryPath = uploaderService.rootPath() + filePath;List<MultipartFile> files = params.getFiles("file");String fileParentPaths = params.getParameter("names");String[] fileParentPathArr = null;if (StringUtils.isNoneBlank(fileParentPaths)) {fileParentPathArr = fileParentPaths.split(",");}//上传人 用户名 用于给上传文件夹赋权限  实际取此处写死模拟String userName ="SHANC";for (int i = 0; files.size() > i; i++) {MultipartFile multipartFile = files.get(i);String originalFilename = "/" + multipartFile.getOriginalFilename();originalFilename = StringUtils.isNotBlank(fileParentPaths) && fileParentPathArr != null ? fileParentPathArr[i] : originalFilename;System.out.println("文件上传路径为:" + targetDirectoryPath + originalFilename);File file = new File(targetDirectoryPath + originalFilename);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}try {multipartFile.transferTo(file);} catch (Exception e) {e.printStackTrace();}}if (StringUtils.isNoneBlank(userName)) {new Thread(() -> FileUploadUtils.chown(userName, targetDirectoryPath)).start();}} catch (Exception e) {e.printStackTrace();}return true;}

用的工具类FileUploadUtils

package com.cloud.user.util;import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.system.OsInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.DecimalFormat;@Slf4j
public class FileUploadUtils {/*** 点*/public static final String DOT = ".";/*** 直接预览的文件类型(不通过LibreOffice转换)*/public static final String PDF = "pdf";private static String transfer(MultipartFile file, File targetFile) {try {file.transferTo(targetFile);} catch (IllegalStateException | IOException e) {e.printStackTrace();}return targetFile.getPath();}private static void mkParentFile(File targetFile) {if (!targetFile.getParentFile().exists()) {targetFile.getParentFile().mkdirs();}}public static String readableFileSize(long size) {if (size <= 0) {return "0";}final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};int digitGroups = (int) (Math.log10(size) / Math.log10(1024));return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];}/*** 文件上传** @param file     文件* @param filePath 文件路径* @return 文件路径*/public static String upload(MultipartFile file, String filePath) {File targetFile = new File(filePath, file.getOriginalFilename().replaceAll(" ", ""));mkParentFile(targetFile);return transfer(file, targetFile);}/*** 处理文件上传** @param file       上传的文件* @param targetFile 目标文件* @return 上传文件目录*/public static String upload(MultipartFile file, File targetFile) {mkParentFile(targetFile);return transfer(file, targetFile);}/*** 批量删除文件或文件夹** @param filePaths 文件路径*/public static void deletes(String[] filePaths) {for (String path : filePaths) {delete(path);}}/*** 删除文件或文件夹** @param filePath 文件路径* @return 成功与否*/public static boolean delete(String filePath) {return FileUtil.del(new File(filePath));}/*** 处理文件上传** @param file        文件* @param filePath    文件路径* @param newFileName 新文件名称* @return 文件大小*/public static Long uploadFileContinue(MultipartFile file, String filePath, String newFileName) {// 记录当前文件大小,用于判断文件是否上传完成long currentFileLength = 0;try {String fileName = file.getOriginalFilename();RandomAccessFile randomAccessfile;// 获取文件的扩展名String ext = "";if (!StringUtils.isEmpty(fileName)) {ext = fileName.substring(fileName.lastIndexOf(DOT));}File newFile = new File(filePath + newFileName + ext);if (!newFile.getParentFile().exists()) {newFile.getParentFile().mkdirs();}// 存在文件if (newFile.exists()) {randomAccessfile = new RandomAccessFile(newFile, "rw");} else {// 不存在文件,根据文件标识创建文件randomAccessfile = new RandomAccessFile(filePath + newFileName + ext, "rw");}// 开始文件传输InputStream in = file.getInputStream();if (randomAccessfile.length() < file.getInputStream().available()) {randomAccessfile.seek(randomAccessfile.length());in.skip(randomAccessfile.length());byte[] b = new byte[1024];int n;while ((n = in.read(b)) != -1) {randomAccessfile.write(b, 0, n);}}currentFileLength = randomAccessfile.length();// 关闭文件closeRandomAccessFile(randomAccessfile);} catch (Exception e) {e.printStackTrace();}return currentFileLength;}/*** 关闭随机访问文件** @param randomAccessFile 随机访问的文件*/private static void closeRandomAccessFile(RandomAccessFile randomAccessFile) {if (null != randomAccessFile) {try {randomAccessFile.close();} catch (Exception e) {e.printStackTrace();}}}/*** 转换PDF文件** @param filePath 当前文件路径* @return PDF文件转换的全路径*/public static String convertToPDF(String filePath, String targetPath) {log.info("filePath:{}", filePath);log.info("targetPath:{}", targetPath);String windowsPath = "D:/apache-tomcat-8.5.64/webapps/upload/";String command = null;String pdfPath = null;if (isLinux()) {command = "/usr/bin/libreoffice6.1 --headless --invisible --convert-to pdf " + filePath + " --outdir " + targetPath;pdfPath = targetPath + "/" + changeSuffix(filePath, PDF);} else if (isWindows()) {command = "cmd /c start soffice --headless --invisible --convert-to pdf:writer_pdf_Export " + filePath + " --outdir " + windowsPath;pdfPath = windowsPath + changeSuffix(filePath, PDF);}System.out.println("pdf command:  " + command);Process exec = RuntimeUtil.exec(command);try {long startTime = System.currentTimeMillis();exec.waitFor();System.out.println("等待时长:" + (System.currentTimeMillis() - startTime));} catch (InterruptedException e) {e.printStackTrace();}return pdfPath;}/*** 更改文件后缀** @param filePath 当前文件路径* @param suffix   后缀* @return 更改后的文件名*/public static String changeSuffix(String filePath, String suffix) {return getPrefix(filePath) + DOT + suffix;}/*** 判断当前OS的类型** @return boolean*/public static boolean isWindows() {return new OsInfo().isWindows();}/*** 判断当前OS的类型** @return boolean*/public static boolean isLinux() {return new OsInfo().isLinux();}/*** 根据文件名检查文件类型,忽略大小写** @param fileName 文件名,例如hutool.png* @param extNames 被检查的扩展名数组,同一文件类型可能有多种扩展名,扩展名不带“.”* @return 是否是指定扩展名的类型*/public static boolean isType(String fileName, String... extNames) {return FileNameUtil.isType(fileName, extNames);}/*** 获取文件名(包含后缀名)** @return 文件名*/public static String getName(String filePath) {return FileNameUtil.getName(filePath);}/*** 获取前缀名** @return 文件前缀名*/public static String getPrefix(String filePath) {return FileNameUtil.getPrefix(filePath);}/*** 获取后缀名(不包括 ".")** @return 文件后缀名*/public static String getSuffix(String filePath) {return FileNameUtil.getSuffix(filePath);}/*** 文件复制(不覆盖目标文件)** @param srcPath  源文件* @param destPath 目标文件*/public static File copy(String srcPath, String destPath) {return FileUtil.copy(srcPath, destPath, false);}//    public static void main(String[] args) {
//        copy("C:\\Users\\lenovo\\Desktop\\123","C:\\Users\\lenovo\\Desktop\\456");
//    }/*** 取得OS的文件路径的分隔符(取自系统属性:<code>file.separator</code>)。** <p>* 例如:Unix为<code>"/"</code>,Windows为<code>"\\"</code>。* </p>** @return 属性值,如果不能取得(因为Java安全限制)或值不存在,则返回<code>null</code>。*/public static String getFileSeparator() {return new OsInfo().getFileSeparator();}public static void downloadFile(HttpServletRequest request, HttpServletResponse response, InputStream inputStream, String fileName) {try (OutputStream os = response.getOutputStream();BufferedInputStream bis = new BufferedInputStream(inputStream);BufferedOutputStream bos = new BufferedOutputStream(os)) {// 处理下载文件名的乱码问题(根据浏览器的不同进行处理)if (request.getHeader("User-Agent").toLowerCase().indexOf("firefox") > 0) {fileName = new String(fileName.getBytes("GB2312"), "ISO-8859-1");} else {// 对文件名进行编码处理中文问题fileName = java.net.URLEncoder.encode(fileName, "UTF-8");// 处理中文文件名的问题fileName = new String(fileName.getBytes("UTF-8"), "GBK");// 处理中文文件名的问题}response.reset();response.setCharacterEncoding("UTF-8");response.setContentType("application/x-msdownload");// 不同类型的文件对应不同的MIME类型response.setHeader("Content-Disposition", "attachment;filename=" + fileName);int bytesRead = 0;byte[] buffer = new byte[4096];while ((bytesRead = bis.read(buffer)) != -1) {bos.write(buffer, 0, bytesRead);bos.flush();}} catch (Exception ex) {throw new RuntimeException(ex.getMessage());}}/*** 删除单个文件** @param sPath 被删除文件的文件名* @return 单个文件删除成功返回true,否则返回false*/public static boolean deleteFile(String sPath) {boolean flag = false;File file = new File(sPath);// 路径为文件且不为空则进行删除if (file.isFile() && file.exists()) {file.delete();flag = true;}return flag;}/*** 删除目录(文件夹)以及目录下的文件** @param path 被删除目录的文件路径* @return 目录删除成功返回true,否则返回false*/public static boolean deleteDirectory(String path) {File dirFile = new File(path);// 如果dir对应的文件不存在,或者不是一个目录,则退出if (!dirFile.exists() || !dirFile.isDirectory()) {return false;}boolean flag = true;// 删除文件夹下的所有文件(包括子目录)File[] files = dirFile.listFiles();for (int i = 0; i < files.length; i++) {if (files[i].isFile()) {// 删除子文件flag = deleteFile(files[i].getAbsolutePath());if (!flag) {break;}} else {// 删除子目录flag = deleteDirectory(files[i].getAbsolutePath());if (!flag) {break;}}}if (!flag) {return false;}if (dirFile.delete()) {// 删除当前目录return true;} else {return false;}}public static void chown(String userName, String path) {String run = RuntimeUtils.execute("id -u " + userName);String run2 = RuntimeUtils.execute("id -g " + userName);RuntimeUtils.execute("chown -R " + run + ":" + run2 + " " + path);}}

此处用Apipost模拟下

 


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

相关文章

HTTP传输大文件

一 概述 早期网络传输的文件非常小&#xff0c;只是一些几K大小的文本和图片&#xff0c;随着网络技术的发展&#xff0c;传输的不仅有几M的图片&#xff0c;还有可以达到几G和几十G的视频。 在这些大文件传输的情况下&#xff0c;100M的光纤或者4G移动网络都会因为网络压力导致…

使用python读取大文件

读取文件时&#xff0c;如果文件过大&#xff0c;则一次读取全部内容到内存&#xff0c;容易造成内存不足&#xff0c;所以要对大文件进行批量的读取内容。 python读取大文件通常两种方法&#xff1a;第一种是利用yield生成器读取&#xff1b;第二种是&#xff1a;利用open()自…

前端必学 - 大文件上传如何实现

前端必学 - 大文件上传如何实现 写在前面问题分析开始操作一、文件如何切片二、得到原文件的hash值三、文件上传四、文件合并 技术点总结【重要】一、上传文件&#xff1f;二、显示进度三、暂停上传四、Hash有优化空间吗&#xff1f;五、限制请求个数六、拥塞控制&#xff0c;动…

Linux如何快速生成大文件

微信搜索&#xff1a;“二十同学” 公众号&#xff0c;欢迎关注一条不一样的成长之路 dd命令 dd if/dev/zero offile bs1M count20000 会生成一个20G的file 文件&#xff0c;文件内容为全0&#xff08;因从/dev/zero中读取&#xff0c;/dev/zero为0源&#xff09;。 此命令可…

java 处理大文件

目的&#xff1a; 前几天在开发过程中遇到一个需求: 读取一个大约5G的csv文件内容&#xff0c;将其转化为对象然后存储到redis中, 想着直接开大内存直接load 进入到内存中就行了&#xff0c;结果可想而知,5G的文件 &#xff0c;Xmx 开到10G都没有解决&#xff0c;直接out of Me…

5、Linux:如何将大文件切割成多份小文件

最近&#xff0c;在做数据文件的导入操作时&#xff0c;发现有些文本文件太大了&#xff0c;需要将这样的大文件切分成多个小文件进行操作。那么&#xff0c;Linux 中如何将大文件切割成许多的小文件呢&#xff1f;在此记录一下。 Linux 提供了 split 命令可以轻松实现大文件的…

大文件传输有哪些方式可用?大文件传输有哪些方式?

大文件传输有哪些方式可用&#xff1f;大文件传输有哪些方式&#xff1f;互联网时代&#xff0c;速度决定效率。在企业生产过程中需要进行信息数据交换、搬运。这时就需要进行大文件传输。方方面面的行业都要涉及到大文件传输。例如影视行业需要每天进行视频素材的传输&#xf…

简道云-第5章-流程

title: 简道云-第5章-流程 date: 2022-06-13 22:21:29 tags: 简道云 categories: 简道云 简道云-第5章-流程 背景介绍 简道云三个基本项目表单、流程以及仪表。关于它们的介绍可以参照官方文档表单 vs 流程表单 vs 仪表盘。 「流程表单」&#xff1a;填报数据&#xff0c;并带…

阿里云【达摩院特别版·趣味视觉AI训练营】笔记2

阿里云【趣味视觉AI训练营】笔记2 一、笔记说明二、正文2.1 人体分割实验2.2 图像人脸融合实验 三、转载说明 一、笔记说明 本博客专栏《阿里云【达摩院特别版趣味视觉AI训练营】》的所有文章均为趣味视觉AI训练营的学习笔记&#xff0c;当前【达摩院特别版趣味视觉AI训练营】…

笔记本简单使用eNSP的云连接外网

文章目录 前言一、连接拓扑图二、配置cloud 三、配置pc测试是否能连接外网 前言 很多时候ping不通的原因不是网卡问题&#xff0c;而是配置没有设置好 一、连接拓扑图 二、配置cloud 绑定信息为UDP然后点击增加 绑定信息 笔记本电脑可以选择WiFi-ip&#xff0c;有本地连接可以…

头歌-信息安全技术-用Python实现自己的区块链、支持以太坊的云笔记服务器端开发、编写并测试用于保存云笔记的智能合约、支持以太坊的云笔记小程序开发基础

头歌-信息安全技术-用Python实现自己的区块链、支持以太坊的云笔记服务器端开发、编写并测试用于保存云笔记的智能合约、支持以太坊的云笔记小程序开发基础 一、用Python实现自己的区块链1、任务描述2、评测步骤(1)打开终端&#xff0c;输入两行代码即可评测通过 二、支持以太坊…

华为云HCS解决方案笔记HUAWEI CLOUD Stack【面试篇】

目录 HCS方案 一、定义 1、特点 2、优点 二、云服务 1、云管理 2、存储服务 3、网络服务 4、计算服务 5、安全服务 6、灾备服务 7、容器服务 三、应用场景 四、HCS功能层 五、OpenStack网络平面规划 六、ManageOne运维面 1、首页 2、集中监控 3、资源拓扑 …

关于玄武集团MOS云平台的使用笔记

对于该平台感兴趣的可以自己下载开发文档看一下&#xff0c;附上地址: https://download.csdn.net/download/qq_39380192/11182359 1、根据开发手册&#xff0c;MOS云平台给用户提供了关于各种通信服务的接口&#xff0c;用户可以通过调用相关的接口来实现一下几点功能&#x…

巧用git commit搭建云笔记+历史记录本

一、整理笔记的必要性 长期学习过程中&#xff0c;我发现人脑并不擅长记忆&#xff0c;它更擅长思考问题。程序员每天都要学习很多知识&#xff0c;学得快&#xff0c;忘得快很正常。很多东西并不需要记住&#xff0c;况且知识那么多&#xff0c;怎么可能全部记住&#xff1f;…

Aliyun 学习笔记(二)阿里云物联网平台介绍

文章目录 1 阿里云物联网平台1.1 设备接入1.2 设备管理1.3 安全能力1.4 规则引擎 1 阿里云物联网平台 根据阿里云物联网平台文档可以了解到所有有关阿里云物联网平台的介绍。 阿里云物联网平台为设备提供安全可靠的连接通信能力&#xff0c;向下连接海量设备&#xff0c;支撑…

《没道云笔记》开发手记

基本配置 Client&#xff1a;Android Servlet&#xff1a;SAE&#xff08;PHPMySQLStorage&#xff09; Period&#xff1a;2 weeks 项目分析 1.Model: Article.class{int id;String username;String title;String time;String content;} Bean.calss{int[] ids;String u…

《物联网 - 机智云开发笔记》第2章 设备驱动开发

开发板&#xff1a;GoKit3开发板&#xff08;STM32F103&#xff09; 在上一章节&#xff0c;笔者带领大家已经将机智云平台玩起来&#xff0c;本节内容讲带领大家经进一步开发。 在开始讲解之前&#xff0c;有必要先了解的机智云的平台架构。 从上面的架构图可以看到&#xf…

云笔记的使用感受和选择

市场上有很多文章针对云笔记的选择&#xff0c;但经过下载发现可能存在很多虚假广告【求生欲&#xff1a;其实可能是个人使用感受不佳仅表示个人观点】。 为什么选择云笔记 个人比较喜欢(❤ ω ❤)记录学习笔记和生活中的东西。之前选择有道云笔记&#xff0c;但因为最近打开…

基于分布式的云笔记实现(参考某道云笔记)

注&#xff1a; 1&#xff09;云笔记代码可在github上下载&#xff0c;如果对您有用&#xff0c;记得star一下。 2&#xff09;依赖jar包可在以下地址下载jar包&#xff0c;密码&#xff1a;yvkj&#xff0c;放到web/lib下即可 3&#xff09;hdfs配置参考网址 4&#xff09…

高软作业1:云笔记软件调研

写在前面&#xff1a; 选择云笔记作为这次调研对象&#xff0c;是因为看到一位同学作业里关于iOS场景下面的笔记软件对比。这一下子让我想起自己入坑过的各款云笔记应用&#xff0c;他们基本上都拥有云端存储和多端同步的功能&#xff0c;但同时又都存在着各自的优缺点。本来一…