新增 支持压缩包密码 修复LINUX下中文乱码 解压支持文件目录

新增 支持压缩包密码 修复LINUX下中文乱码 解压支持文件目录

Signed-off-by: 高雄 <admin@cxcp.com>
pull/84/head
高雄 2 years ago committed by Gitee
parent 1e771ed649
commit 1807dbd615
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F

@ -1,32 +1,24 @@
package cn.keking.service; package cn.keking.service;
import cn.keking.config.ConfigConstants; import cn.keking.config.ConfigConstants;
import cn.keking.model.FileType; import cn.keking.model.FileType;
import cn.keking.utils.FileHeaderRar;
import cn.keking.utils.KkFileUtils;
import cn.keking.web.filter.BaseUrlFilter; import cn.keking.web.filter.BaseUrlFilter;
import com.fasterxml.jackson.core.JsonProcessingException; import net.sf.sevenzipjbinding.ExtractOperationResult;
import com.fasterxml.jackson.databind.ObjectMapper; import net.sf.sevenzipjbinding.IInArchive;
import com.github.junrar.Archive; import net.sf.sevenzipjbinding.SevenZip;
import com.github.junrar.exception.RarException; import net.sf.sevenzipjbinding.SevenZipException;
import com.github.junrar.rarfile.FileHeader;
import net.sf.sevenzipjbinding.*;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.simple.ISimpleInArchive; import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.*; import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.CollationKey; import java.util.ArrayList;
import java.text.Collator; import java.util.List;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
/** /**
* @author yudian-it * @author yudian-it
@ -34,16 +26,11 @@ import java.util.stream.Collectors;
*/ */
@Component @Component
public class CompressFileReader { public class CompressFileReader {
private static final Pattern pattern = Pattern.compile("^\\d+");
private final FileHandlerService fileHandlerService; private final FileHandlerService fileHandlerService;
private final String fileDir = ConfigConstants.getFileDir();
private final ExecutorService executors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public CompressFileReader(FileHandlerService fileHandlerService) { public CompressFileReader(FileHandlerService fileHandlerService) {
this.fileHandlerService = fileHandlerService; this.fileHandlerService = fileHandlerService;
} }
private static final String fileDir = ConfigConstants.getFileDir();
public static byte[] getUTF8BytesFromGBKString(String gbkStr) { public static byte[] getUTF8BytesFromGBKString(String gbkStr) {
int n = gbkStr.length(); int n = gbkStr.length();
byte[] utfBytes = new byte[3 * n]; byte[] utfBytes = new byte[3 * n];
@ -92,21 +79,15 @@ public class CompressFileReader {
*/ */
private static boolean isChinese(char c) { private static boolean isChinese(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS;
return true;
}
return false;
} }
public static boolean judge(char c){ public static boolean judge(char c){
if((c >='0' && c<='9')||(c >='a' && c<='z' || c >='A' && c<='Z')){ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
return true;
}
return false;
} }
public static boolean isMessyCode(String strName) { public static boolean isMessyCode(String strName) {
//去除字符串中的空格 制表符 换行 回车 //去除字符串中的空格 制表符 换行 回车
@ -117,8 +98,7 @@ public class CompressFileReader {
String temp = after.replaceAll("\\p{P}", ""); String temp = after.replaceAll("\\p{P}", "");
//处理之后转换成字符数组 //处理之后转换成字符数组
char[] ch = temp.trim().toCharArray(); char[] ch = temp.trim().toCharArray();
for (int i = 0; i < ch.length; i++) { for (char c : ch) {
char c = ch[i];
//判断是否是数字或者英文字符 //判断是否是数字或者英文字符
if (!judge(c)) { if (!judge(c)) {
//判断是否是中日韩文 //判断是否是中日韩文
@ -131,74 +111,61 @@ public class CompressFileReader {
//表示不是乱码 返回false //表示不是乱码 返回false
return false; return false;
} }
public String unRar(String paths, String passWord, String fileName) {
public String unRar(String filePath, String fileKey) {
Map<String, FileNode> appender = new HashMap<>();
List<String> imgUrls = new ArrayList<>(); List<String> imgUrls = new ArrayList<>();
String baseUrl = BaseUrlFilter.getBaseUrl(); String baseUrl = BaseUrlFilter.getBaseUrl();
try { String archiveFileName = fileHandlerService.getFileNameFromPath(paths);
List<FileHeaderRar> items = getRar4Paths(filePath);
String archiveFileName = fileHandlerService.getFileNameFromPath(filePath);
List<Map<String, FileHeaderRar>> headersToBeExtract = new ArrayList<>();
for (FileHeaderRar header : items) {
String fullName = header.getFileNameW();
String originName = getLastFileName(fullName);
String childName = originName;
boolean directory = header.getDirectory();
if (!directory) {
childName = archiveFileName + "_" + originName;
headersToBeExtract.add(Collections.singletonMap(childName, header));
}
String parentName = getLast2FileName(fullName, archiveFileName);
FileType type = FileType.typeFromUrl(childName);
if (type.equals(FileType.PICTURE)) {
imgUrls.add(baseUrl + childName);
}
FileNode node =
new FileNode(originName, childName, parentName, new ArrayList<>(), directory, fileKey);
addNodes(appender, parentName, node);
appender.put(childName, node);
}
fileHandlerService.putImgCache(fileKey, imgUrls);
executors.submit(new RarExtractorWorker(headersToBeExtract, filePath));
return new ObjectMapper().writeValueAsString(appender.get(""));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public List<FileHeaderRar> getRar4Paths(String paths) {
RandomAccessFile randomAccessFile = null; RandomAccessFile randomAccessFile = null;
IInArchive inArchive = null; IInArchive inArchive = null;
List<FileHeaderRar> itemPath = null;
try { try {
randomAccessFile = new RandomAccessFile(paths, "r"); randomAccessFile = new RandomAccessFile(paths, "r");
inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile)); inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile));
String folderName = paths.substring(paths.lastIndexOf(File.separator) + 1); String folderName = paths.substring(paths.lastIndexOf(File.separator) + 1);
String extractPath = paths.substring(0, paths.lastIndexOf(folderName)); String extractPath = paths.substring(0, paths.lastIndexOf(folderName));
inArchive.extract(null, false, new ExtractCallback(inArchive, extractPath, folderName + "_")); ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();
ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface(); final String[] str = {null};
itemPath = Arrays.stream(simpleInArchive.getArchiveItems()).map(o -> { for (final ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {
try { if (!item.isFolder()) {
String path = getUtf8String(o.getPath()); ExtractOperationResult result;
if (isMessyCode(path)){ result = item.extractSlow(data -> {
path = new String(o.getPath().getBytes(StandardCharsets.ISO_8859_1), "GBK"); try {
} str[0] = getUtf8String(item.getPath());
return new FileHeaderRar(path, o.isFolder()); if (isMessyCode(str[0])){
} catch (SevenZipException e) { str[0] = new String(item.getPath().getBytes(StandardCharsets.ISO_8859_1), "gbk");
e.printStackTrace(); }
} catch (UnsupportedEncodingException e) { str[0] = str[0].replace("\\", File.separator); //Linux 下路径错误
e.printStackTrace(); String str1 = str[0].substring(0, str[0].lastIndexOf(File.separator)+ 1);
} File file = new File(extractPath, folderName + "_" + File.separator + str1);
return null; if (!file.exists()) {
}) file.mkdirs();
.collect(Collectors.toList()) }
.stream() OutputStream out = new FileOutputStream( extractPath+ folderName + "_" + File.separator + str[0], true);
.sorted(Comparator.comparing(FileHeaderRar::getFileNameW)) IOUtils.write(data, out);
.collect(Collectors.toList()); out.close();
} catch (Exception e) {
e.printStackTrace();
}
return data.length;
}, passWord);
if (result == ExtractOperationResult.OK) {
FileType type = FileType.typeFromUrl(str[0]);
if (type.equals(FileType.PICTURE)) {
// System.out.println( baseUrl +folderName + "_" + str[0]);
imgUrls.add(baseUrl +folderName + "_/" + str[0].replace("\\", "/"));
}
fileHandlerService.putImgCache(fileName, imgUrls);
} else {
return "error";
}
}
}
return archiveFileName + "_";
} catch (Exception e) { } catch (Exception e) {
System.err.println("Error occurs: " + e); String Str1 = String.valueOf(e);
if (Str1.contains("Password")) {
return "Password";
}
return null;
} finally { } finally {
if (inArchive != null) { if (inArchive != null) {
try { try {
@ -215,276 +182,34 @@ public class CompressFileReader {
} }
} }
} }
return itemPath;
} }
/**
private void addNodes(Map<String, FileNode> appender, String parentName, FileNode node) { *
if (appender.containsKey(parentName)) { */
appender.get(parentName).getChildList().add(node); public static List<ZtreeNodeVo> getTree(String rootPath) {
appender.get(parentName).getChildList().sort(sortComparator); List<ZtreeNodeVo> nodes = new ArrayList<>();
} else { File file = new File(fileDir+rootPath);
// 根节点 ZtreeNodeVo node = traverse(file);
FileNode nodeRoot = new FileNode(parentName, parentName, "", new ArrayList<>(), true); nodes.add(node);
nodeRoot.getChildList().add(node); return nodes;
appender.put("", nodeRoot);
appender.put(parentName, nodeRoot);
}
}
private static String getLast2FileName(String fullName, String rootName) {
if (fullName.endsWith(File.separator)) {
fullName = fullName.substring(0, fullName.length() - 1);
}
// 1.获取剩余部分
int endIndex = fullName.lastIndexOf(File.separator);
String leftPath = fullName.substring(0, endIndex == -1 ? 0 : endIndex);
if (leftPath.length() > 1) {
// 2.获取倒数第二个
return getLastFileName(leftPath);
} else {
return rootName;
}
}
private static String getLastFileName(String fullName) {
if (fullName.endsWith(File.separator)) {
fullName = fullName.substring(0, fullName.length() - 1);
}
String newName = fullName;
if (fullName.contains(File.separator)) {
newName = fullName.substring(fullName.lastIndexOf(File.separator) + 1);
}
return newName;
}
public static Comparator<FileNode> sortComparator = new Comparator<FileNode>() {
final Collator cmp = Collator.getInstance(Locale.US);
@Override
public int compare(FileNode o1, FileNode o2) {
// 判断两个对比对象是否是开头包含数字,如果包含数字则获取数字并按数字真正大小进行排序
BigDecimal num1, num2;
if (null != (num1 = isStartNumber(o1))
&& null != (num2 = isStartNumber(o2))) {
return num1.subtract(num2).intValue();
}
CollationKey c1 = cmp.getCollationKey(o1.getOriginName());
CollationKey c2 = cmp.getCollationKey(o2.getOriginName());
return cmp.compare(c1.getSourceString(), c2.getSourceString());
}
};
private static BigDecimal isStartNumber(FileNode src) {
Matcher matcher = pattern.matcher(src.getOriginName());
if (matcher.find()) {
return new BigDecimal(matcher.group());
}
return null;
}
public static class FileNode {
private String originName;
private String fileName;
private String parentFileName;
private boolean directory;
//用于图片预览时寻址
private String fileKey;
private List<FileNode> childList;
public FileNode(String originName, String fileName, String parentFileName, List<FileNode> childList, boolean directory) {
this.originName = originName;
this.fileName = fileName;
this.parentFileName = parentFileName;
this.childList = childList;
this.directory = directory;
}
public FileNode(String originName, String fileName, String parentFileName, List<FileNode> childList, boolean directory, String fileKey) {
this.originName = originName;
this.fileName = fileName;
this.parentFileName = parentFileName;
this.childList = childList;
this.directory = directory;
this.fileKey = fileKey;
}
public String getFileKey() {
return fileKey;
}
public void setFileKey(String fileKey) {
this.fileKey = fileKey;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getParentFileName() {
return parentFileName;
}
public void setParentFileName(String parentFileName) {
this.parentFileName = parentFileName;
}
public List<FileNode> getChildList() {
return childList;
}
public void setChildList(List<FileNode> childList) {
this.childList = childList;
}
@Override
public String toString() {
try {
return new ObjectMapper().writeValueAsString(this);
} catch (JsonProcessingException e) {
e.printStackTrace();
return "";
}
}
public String getOriginName() {
return originName;
}
public void setOriginName(String originName) {
this.originName = originName;
}
public boolean isDirectory() {
return directory;
}
public void setDirectory(boolean directory) {
this.directory = directory;
}
} }
private static ZtreeNodeVo traverse(File file) {
class RarExtractorWorker implements Runnable { ZtreeNodeVo pathNodeVo = new ZtreeNodeVo();
private final List<Map<String, FileHeader>> headersToBeExtracted; pathNodeVo.setId(file.getAbsolutePath().replace(fileDir, "").replace("\\", "/"));
pathNodeVo.setName(file.getName());
private final List<Map<String, FileHeaderRar>> headersToBeExtract; pathNodeVo.setPid(file.getParent().replace(fileDir, "").replace("\\", "/"));
if (file.isDirectory()) {
private final Archive archive; List<ZtreeNodeVo> subNodeVos = new ArrayList<>();
/** File[] subFiles = file.listFiles();
* if (subFiles == null) {
*/ return pathNodeVo;
private final String filePath;
public RarExtractorWorker(
List<Map<String, FileHeader>> headersToBeExtracted, Archive archive, String filePath) {
this.headersToBeExtracted = headersToBeExtracted;
this.archive = archive;
this.filePath = filePath;
headersToBeExtract = null;
}
public RarExtractorWorker(
List<Map<String, FileHeaderRar>> headersToBeExtract, String filePath) {
this.headersToBeExtract = headersToBeExtract;
this.filePath = filePath;
archive = null;
headersToBeExtracted = null;
}
@Override
public void run() {
for (Map<String, FileHeader> entryMap : headersToBeExtracted) {
String childName = entryMap.keySet().iterator().next();
extractRarFile(childName, entryMap.values().iterator().next(), archive);
}
try {
archive.close();
} catch (IOException e) {
e.printStackTrace();
} }
KkFileUtils.deleteFileByPath(filePath); for (File subFile : subFiles) {
} ZtreeNodeVo subNodeVo = traverse(subFile);
subNodeVos.add(subNodeVo);
private void extractRarFile(String childName, FileHeader header, Archive archive) {
String outPath = fileDir + childName;
try (OutputStream ot = new FileOutputStream(outPath)) {
archive.extractFile(header, ot);
} catch (IOException | RarException e) {
e.printStackTrace();
} }
pathNodeVo.setChildren(subNodeVos);
} }
} return pathNodeVo;
private static class ExtractCallback implements IArchiveExtractCallback {
private final IInArchive inArchive;
private final String extractPath;
private final String folderName;
public ExtractCallback(IInArchive inArchive, String extractPath, String folderName) {
this.inArchive = inArchive;
if (!extractPath.endsWith("/") && !extractPath.endsWith("\\")) {
extractPath += File.separator;
}
this.extractPath = extractPath;
this.folderName = folderName;
}
@Override
public void setTotal(long total) {
}
@Override
public void setCompleted(long complete) {
}
@Override
public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
String filePath = inArchive.getStringProperty(index, PropID.PATH);
String real = folderName + filePath.substring(filePath.lastIndexOf(File.separator) + 1);
File f = new File(extractPath + real);
f.delete();
return data -> {
FileOutputStream fos = null;
try {
File path = new File(extractPath + real);
if (!path.getParentFile().exists()) {
path.getParentFile().mkdirs();
}
if (!path.exists()) {
path.createNewFile();
}
fos = new FileOutputStream(path, true);
fos.write(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.flush();
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return data.length;
};
}
@Override
public void prepareOperation(ExtractAskMode extractAskMode) {
}
@Override
public void setOperationResult(ExtractOperationResult extractOperationResult) {
}
} }
} }

Loading…
Cancel
Save