package com.test.file.utils;
import com.test.commons.rest.RestErrorEnum;
import com.test.commons.rest.RestException;
import com.test.file.entity.FileInfo;
import com.test.filestruct.plm.file.DocxStructExplorer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.poi.util.IOUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Slf4j
public class CustomFileUtils {
// office
private static String[] office = {"word", "excel", "ppt"};
// excel
private static String[] etExts = {"et", "xls", "xlt", "xlsx", "xlsm", "xltx", "xltm", "csv"};
// word
private static String[] wpsExts = {"doc", "docx", "txt", "dot", "wps", "wpt", "dotx", "docm", "dotm"};
// ppt
private static String[] wppExts = {"ppt", "pptx", "pptm", "pptm", "ppsm", "pps", "potx", "potm", "dpt", "dps"};
// pdf
private static String[] pdfExts = {"pdf"};
public static String getFileTypeCode(String fileType) {
for (String et : etExts) {
if (et.equalsIgnoreCase(fileType)) {
return "s";
}
}
for (String et : wpsExts) {
if (et.equalsIgnoreCase(fileType)) {
return "w";
}
}
for (String et : wppExts) {
if (et.equalsIgnoreCase(fileType)) {
return "p";
}
}
for (String et : pdfExts) {
if (et.equalsIgnoreCase(fileType)) {
return "f";
}
}
return null;
}
public static boolean checkCode(String fileType) {
for (String et : office) {
if (et.equalsIgnoreCase(fileType)) {
return true;
}
}
return false;
}
public static String getTypeCode(String fileType) {
if ("word".equalsIgnoreCase(fileType)) {
return "w";
}
if ("excel".equalsIgnoreCase(fileType)) {
return "s";
}
if ("ppt".equalsIgnoreCase(fileType)) {
return "p";
}
return null;
}
public static String getFileName(String filePath) {
String[] pathArr = filePath.split("/");
String fileName;
if (pathArr.length > 1) {
fileName = pathArr[pathArr.length - 1];
} else {
fileName = filePath;
}
return fileName;
}
public static String getFileTypeByPath(String filePath) {
String fileName = getFileName(filePath);
String[] arr = fileName.split("\\.");
return arr[arr.length - 1];
}
public static String getFileTypeByName(String fileName) {
String[] arr = fileName.split("\\.");
return arr[arr.length - 1];
}
public static String getFileUUIDName(String fileName, String fileType) {
String uuid = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
String uuidFileName = fileName.replace(".", "").replace(fileType, "") + uuid + "." + fileType;
return new String(uuidFileName.getBytes(), StandardCharsets.UTF_8);
}
/**
* 文件上传功能
*
* @param file
* @param path 文件路径
*/
public static void uploadFile(MultipartFile file, String path) {
try {
File dest = new File(path);
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
file.transferTo(dest);
// 加密上传文件
DocxStructExplorer.encryptFile(dest);
} catch (IOException e) {
log.error(e.getMessage());
throw new RestException(RestErrorEnum.FILE_UPLOAD_FAIL);
}
}
/*public static String makeNewFileName(String oldFileName){
String fileType = getFileTypeByName(oldFileName);
String tempFileName = oldFileName.replace("."+fileType,"");
Random ne = new Random();//实例化一个random的对象ne
int uuid = ne.nextInt(90000)+10000;//为变量赋随机值10000-99999
return tempFileName + uuid + "." + fileType;
}
public static String makeNewFileName(String oldFileName,String fileType){
String tempFileName = oldFileName.replace("."+fileType,"");
Random ne = new Random();//实例化一个random的对象ne
int uuid = ne.nextInt(90000)+10000;//为变量赋随机值10000-99999
return tempFileName + uuid + "." + fileType;
}*/
/**
* 文件下载
*
* @param path 文件路径
* @param request
* @param response
* @param fileName 文件名称
*/
public static void download(String path, HttpServletRequest request, HttpServletResponse response, String fileName) {
File file = new File(path);
try {
// 获取加密文件解密之后的字节数组信息
byte[] data = DocxStructExplorer.decryptFile(file);
download(data, request, response, fileName);
} catch (IOException e) {
log.error("解密文件{}异常,{}", fileName, e.getMessage());
}
}
public static String getApplicationPath() {
/*ApplicationHome h = new ApplicationHome(XeleratorApplication.class);
File jarFile = h.getSource();
return jarFile.getParentFile().getPath();*/
return System.getProperty("user.dir");
}
public static void download(File file, HttpServletRequest request, HttpServletResponse response, String fileName) {
if (file.exists()) {
setHeader(request, response, fileName);
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
IOUtils.copy(fis, response.getOutputStream());
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public static void download(byte[] data, HttpServletRequest request, HttpServletResponse response, String fileName) {
if (data != null) {
setHeader(request, response, fileName);
FileInputStream fis = null;
try {
ServletOutputStream out = response.getOutputStream();
out.write(data);
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* @param zipFile
* @param srcFiles
*/
public static void toZip(File zipFile, List<FileInfo> srcFiles) {
ZipOutputStream zos = null;
try {
// 构造最终压缩包输出流
zos = new ZipOutputStream(new FileOutputStream(zipFile));
putFile(zos, srcFiles, null);
} catch (Exception e) {
log.error(e.getMessage());
throw new RestException(RestErrorEnum.FILE_DOWNLOAD_FAIL);
} finally {
if (zos != null) {
try {
zos.close();
} catch (IOException e) {
log.error(e.getMessage());
e.printStackTrace();
}
}
}
}
public static void putFile(ZipOutputStream zos, List<FileInfo> srcFiles, String path) throws IOException {
path = StringUtils.isEmpty(path) ? "" : path;
/*if(path.endsWith("/")){
path = path.substring(0, path.length() - 1);
}*/
for (FileInfo srcFile : srcFiles) {
putPrivateFile(zos, path + URLDecoder.decode(srcFile.getName(), "UTF-8"), srcFile.getPath());
}
}
public static void putPrivateFile(ZipOutputStream zos, String name, String path) throws IOException {
zos.putNextEntry(new ZipEntry(name));
// 获取加密文件解密后自己数组
byte[] data = DocxStructExplorer.decryptFile(new File(path));
InputStream input = new ByteArrayInputStream(data);
IOUtils.copy(input, zos);
zos.closeEntry();
if (input != null) {
input.close();
}
}
public static void putPublicFile(ZipOutputStream zos, String name, String path) throws IOException {
zos.putNextEntry(new ZipEntry(name));
// 获取加密文件解密后自己数组
InputStream input = new FileInputStream(new File(path));
IOUtils.copy(input, zos);
zos.closeEntry();
if (input != null) {
input.close();
}
}
public static void putPublicFile(ZipOutputStream zos, File file) throws IOException {
zos.putNextEntry(new ZipEntry(file.getName()));
// 获取加密文件解密后自己数组
InputStream input = new FileInputStream(file);
IOUtils.copy(input, zos);
zos.closeEntry();
if (input != null) {
input.close();
}
}
/**
* 压缩文件目录
*
* @param source 源文件目录(单个文件和多层目录)
* @param dest 目标目录
*/
public static void zipFiles(String source, String dest) {
File file = new File(source);
ZipOutputStream zipOutputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(dest);
zipOutputStream = new ZipOutputStream(fileOutputStream);
if (file.isDirectory()) {
directory(zipOutputStream, file, "");
} else {
zipDirectoryFile(zipOutputStream, file, "");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
zipOutputStream.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 递归压缩目录结构
*
* @param zipOutputStream
* @param file
* @param parentFileName
*/
public static void directory(ZipOutputStream zipOutputStream, File file, String parentFileName) {
File[] files = file.listFiles();
String parentFileNameTemp = null;
for (File fileTemp : files) {
parentFileNameTemp = StringUtils.isEmpty(parentFileName) ? fileTemp.getName() : parentFileName + "/" + fileTemp.getName();
if (fileTemp.isDirectory()) {
directory(zipOutputStream, fileTemp, parentFileNameTemp);
} else {
zipDirectoryFile(zipOutputStream, fileTemp, parentFileNameTemp);
}
}
}
public static void zipDirectoryFile(ZipOutputStream zipOutputStream, File file, String parentFileName) {
FileInputStream in = null;
try {
ZipEntry zipEntry = new ZipEntry(parentFileName);
zipOutputStream.putNextEntry(zipEntry);
in = new FileInputStream(file);
int len;
byte[] buf = new byte[8 * 1024];
while ((len = in.read(buf)) != -1) {
zipOutputStream.write(buf, 0, len);
}
zipOutputStream.closeEntry();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static boolean unZip(String zip, String targetPath) {
ZipFile zipFile = null;
int BUFFER_SIZE = 1024;
try {
zipFile = new ZipFile(zip, "gbk");//一般window用户默认是GBK,如果要更改编码,需要用winrar等软件压缩
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
ZipArchiveEntry entry = null;
while (entries.hasMoreElements()) {
entry = entries.nextElement();
if (entry.isDirectory()) {
File directory = new File(targetPath, entry.getName());
directory.mkdirs();
} else {
File file = new File(targetPath, entry.getName());
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
InputStream is = zipFile.getInputStream(entry);
OutputStream os = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE);
IOUtils.copy(is, os);
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(is);
}
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
zipFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static boolean setHeader(HttpServletRequest request, HttpServletResponse response, String fileName) {
try {
response.setContentType("application/octet-stream");
response.setHeader("content-type", "application/octet-stream");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
String browser = request.getHeader("User-Agent");
if (-1 < browser.indexOf("MSIE 6.0") || -1 < browser.indexOf("MSIE 7.0")) {
// IE6, IE7 浏览器
response.addHeader("content-disposition", "attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1"));
} else if (-1 < browser.indexOf("MSIE 8.0")) {
// IE8
response.addHeader("content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")
.replaceAll("\\+", " "));
} else if (-1 < browser.indexOf("MSIE 9.0")) {
// IE9
response.addHeader("content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")
.replaceAll("\\+", " "));
} else if (-1 < browser.indexOf("Chrome")) {
// 谷歌
response.addHeader("content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")
.replaceAll("\\+", " "));
} else if (-1 < browser.indexOf("Safari")) {
// 苹果
response.addHeader("content-disposition", "attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1"));
} else {
// 火狐或者其他的浏览器
response.addHeader("content-disposition", "attachment; filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8")
.replaceAll("\\+", " "));
}
return true;
} catch (Exception e) {
log.error(e.getMessage());
return false;
}
}
public static void deleteFile(String path) {
File file = new File(path);
if (file != null && file.exists() && file.isFile()) {
if (file.delete()) {
log.info("删除" + path + "草稿文档成功");
} else {
log.error("删除" + path + "草稿文档失败");
}
}
}
public static void setFileStreamToResponse(HttpServletResponse response, File zipFile) throws IOException {
FileInputStream fis = new FileInputStream(zipFile);
// force-download
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(zipFile.getName(), "UTF-8"))));
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setCharacterEncoding("utf-8");
OutputStream os = response.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
os.write(buf, 0, len);
}
fis.close();
os.close();
}
public static void deleteFile(File file) {
if (file != null && file.exists() && file.isFile()) {
if (file.delete()) {
log.info("删除临时文件成功");
} else {
log.error("删除临时文件失败");
}
}
}
/* public class Test {
private static int a = 5;
public static void main(String[] args) {
//需要复制的目标文件或目标文件夹
String pathname = "C:/Users/likun/Desktop/git_project";
File file = new File(pathname);
//复制到的位置
String topathname = "C:/Users/likun/Desktop/movie";
File toFile = new File(topathname);
try {
copy(file, toFile);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
public static void copy(File file, File toFile) throws Exception {
byte[] b = new byte[1024];
int a;
FileInputStream fis;
FileOutputStream fos;
if (file.isDirectory()) {
String filepath = file.getAbsolutePath();
filepath = filepath.replaceAll("\\\\", "/");
String toFilepath = toFile.getAbsolutePath();
toFilepath = toFilepath.replaceAll("\\\\", "/");
int lastIndexOf = filepath.lastIndexOf("/");
toFilepath = toFilepath + filepath.substring(lastIndexOf, filepath.length());
File copy = new File(toFilepath);
//复制文件夹
if (!copy.exists()) {
copy.mkdir();
}
//遍历文件夹
for (File f : file.listFiles()) {
copy(f, copy);
}
} else {
if (toFile.isDirectory()) {
String filepath = file.getAbsolutePath();
filepath = filepath.replaceAll("\\\\", "/");
String toFilepath = toFile.getAbsolutePath();
toFilepath = toFilepath.replaceAll("\\\\", "/");
int lastIndexOf = filepath.lastIndexOf("/");
toFilepath = toFilepath + filepath.substring(lastIndexOf, filepath.length());
//写文件
File newFile = new File(toFilepath);
fis = new FileInputStream(file);
fos = new FileOutputStream(newFile);
while ((a = fis.read(b)) != -1) {
fos.write(b, 0, a);
}
} else {
//写文件
fis = new FileInputStream(file);
fos = new FileOutputStream(toFile);
while ((a = fis.read(b)) != -1) {
fos.write(b, 0, a);
}
}
}
}
public static void delDir(File file) {
if (file.isDirectory()) {
File zFiles[] = file.listFiles();
for (File file2 : zFiles) {
delDir(file2);
}
//删除目录
file.delete();
} else {
boolean delete = file.delete();
if(!delete){
log.error("文件删除失败");
}
}
}
}
package com.test.filestruct.plm.file;
import com.test.filestruct.plm.file.exception.EncryptException;
import com.test.filestruct.plm.file.exception.NoContentException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* Word 文件的结构化解析文件处理。
*
* @since 2020-03-16
* @author Dudl
*/
public class DocxStructExplorer {
private static final String STRUCT_PATH = "struct";
private static final String TABLE_PATH = "table";
private static final String PIC_PATH = "pic";
// 线上存储结构化数据的根目录。
private static boolean rootSet;
private static File root = new File(System.getProperty("user.dir") + "/files-prod/docx-struct");
/**
* 设置根目录。
* 仅能设置一次。
*
* @param root
*/
public static void setRoot(File root) {
if (!rootSet) {
DocxStructExplorer.root = root;
}
rootSet = true;
}
/**
* 获取存储 PLM 文件的本地目录。
*
* @return
*/
public static File getRoot() {
return root;
}
/**
* 获取临时目录。
*
* @return
*/
public static File getTempPath() {
File file = new File(getRoot(), "temp");
if (!file.exists()) {
file.mkdirs();
}
return file;
}
/**
* 获取项目根目录。
*
* @param projectId
* @return
*/
public static File getProjectRoot(long projectId) {
return new File(getRoot(), projectId + "");
}
/**
* 获取文件的根目录。
*
* @param projectId
* @param fileId
* @return
*/
public static File getFileRoot(long projectId, long fileId) {
return new File(getRoot(), projectId + "/" + fileId);
}
/**
* 获取当前文档独立的本地目录。
*
* @param projectId
* @param fileId
* @param version
* @return
*/
public static File getVersionPath(long projectId, long fileId, String version) {
return new File(getRoot(), projectId + "/" + fileId + "/" + version);
}
/**
* 获取当前文档独立的本地目录。
*
* @param projectId
* @param fileId
* @return
*/
public static File getFilePath(long projectId, long fileId) {
return new File(getRoot(), projectId + "/" + fileId);
}
/**
* 获取保存 Word 结构化内容的目录。
*
* @param projectId
* @param fileId
* @param version
* @return
*/
public static File getStructPath(long projectId, long fileId, String version) {
return new File(getVersionPath(projectId, fileId, version), STRUCT_PATH);
}
public static File getTablePath(long projectId, long fileId) {
return new File(getFilePath(projectId, fileId), TABLE_PATH);
}
/**
* 获取保存指定 Word 文档图片资源的目录。
*
* @param projectId
* @param fileId
* @param version
* @return
*/
public static File getPicPath(long projectId, long fileId, String version) {
return new File(getVersionPath(projectId, fileId, version), PIC_PATH);
}
/**
* 获取指定序号的多媒体本地文件名。
*
* @param index
* @return
*/
private static String getIndexStructFilename(int index) {
return index + ".struct";
}
/**
* 获取指定序号的多媒体本地文件名。
*
* @param index
* @return
*/
private static String getIndexTableFilename(int index) {
return index + ".html";
}
/**
* 获取预览 HTML 的一地文件名。
*
* @return
*/
private static String getViewFilename() {
return "view.html";
}
/**
* 读取该文件,并对文件加密后重新回写。
*
* @param file
* @throws IOException
*/
public static void encryptFile(File file) throws IOException {
if (file.exists()) {
byte[] bytes = FileUtils.readFileToByteArray(file);
if (bytes != null) {
Explorer.writeFile(file, bytes);
}
}
}
/**
* 读取文件并解密。
*
* @param file
* @return
* @throws IOException
*/
public static byte[] decryptFile(File file) throws IOException {
return Explorer.readFile(file);
}
/**
* 读本指定顺序的多媒体文件内容。
*
* @param projectId
* @param fileId
* @param version
* @param index
* @return
* @throws FileNotFoundException
* @throws IOException
*/
public static byte[] readStruct(long projectId, long fileId, String version, int index) throws FileNotFoundException, IOException {
File file = new File(getStructPath(projectId, fileId, version), getIndexStructFilename(index));
return Explorer.readFile(file);
}
/**
* 读本指定顺序的table文件内容。
*
* @param projectId
* @param fileId
* @param index
* @return
* @throws FileNotFoundException
* @throws IOException
*/
public static byte[] readTable(long projectId, long fileId, int index) throws FileNotFoundException, IOException {
File file = new File(getTablePath(projectId, fileId), getIndexTableFilename(index));
return Explorer.readFile(file);
}
/**
* 保存指定顺序多媒体内容到本地。
*
* @param projectId
* @param fileId
* @param version
* @param index
* @param data
* @throws EncryptException
* @throws IOException
*/
public static void writeStruct(long projectId, long fileId, String version, int index, byte[] data) throws EncryptException, IOException {
File file = new File(getStructPath(projectId, fileId, version), getIndexStructFilename(index));
Explorer.writeFile(file, data);
}
/**
* 保存指定顺序table内容到本地。
*
* @param projectId
* @param fileId
* @param index
* @param data
* @throws EncryptException
* @throws IOException
*/
public static void writeTable(long projectId, long fileId, int index, byte[] data) throws EncryptException, IOException {
File file = new File(getTablePath(projectId, fileId), getIndexTableFilename(index));
Explorer.writeFile(file, data);
}
/**
* 读取本地预览 HTML 内容。
*
* @param projectId
* @param fileId
* @param version
* @return
* @throws FileNotFoundException
* @throws IOException
*/
public static String readView(long projectId, long fileId, String version) throws FileNotFoundException, IOException {
File file = new File(getVersionPath(projectId, fileId, version), getViewFilename());
byte[] data = Explorer.readFile(file);
if (data != null) {
return new String(data, StandardCharsets.UTF_8);
}
return null;
}
/**
* 保存本地预览 HTML 文件。
*
* @param projectId
* @param fileId
* @param version
* @param html
* @return
* @throws IOException
*/
public static void writeView(long projectId, long fileId, String version, String html) throws IOException {
if (StringUtils.isEmpty(html)) {
throw new NoContentException();
}
File file = new File(getVersionPath(projectId, fileId, version), getViewFilename());
byte[] bytes = html.getBytes(StandardCharsets.UTF_8);
Explorer.writeFile(file, bytes);
}
/**
* 清除项目所有文件。
*
* @param projectId
* @throws IOException
*/
public static void clearProject(long projectId) throws IOException {
File file = getProjectRoot(projectId);
FileUtils.deleteDirectory(file);
}
/**
* 清除文件所有版本文件。
*
* @param projectId
* @param fileId
*/
public static void clearFile(long projectId, long fileId) throws IOException {
File file = getFileRoot(projectId, fileId);
FileUtils.deleteDirectory(file);
}
/**
* 清除文件指定版本内容。
*
* @param projectId
* @param fileId
* @param version
* @throws IOException
*/
public static void clearVersion(long projectId, long fileId, String version) throws IOException {
clearStruct(projectId, fileId, version);
deleteView(projectId, fileId, version);
}
/**
* 删除指定序号的结构化文件。
*
* @param projectId
* @param fileId
* @param version
* @param index
* @return
*/
public static boolean deleteStruct(long projectId, long fileId, String version, int index) {
return new File(getStructPath(projectId, fileId, version), getIndexStructFilename(index)).delete();
}
/**
* 清除指定文件的所有多媒体内容。
*
* @param projectId
* @param fileId
* @param version
* @return
*/
public static void clearStruct(long projectId, long fileId, String version) throws IOException {
FileUtils.deleteDirectory(getStructPath(projectId, fileId, version));
}
/**
* 删除指定文件的预览文件。
*
* @param projectId
* @param fileId
* @param version
* @return
*/
public static boolean deleteView(long projectId, long fileId, String version) {
return new File(getVersionPath(projectId, fileId, version), getViewFilename()).delete();
}
}
1.CustomFileUtils :文件操作,当中的自定义异常类本文中没有写入,参考者可自行替换
2.DocxStructExplorer:word 文件的相关处理,文件操作的工具类中有调用本类的加密、解密方法