javaMultipartFile上传⽂件,JDK⾃带ZIP中⽂问题,以及Zip4J
介绍和使⽤
最近遇到⼀个这样的需求:传⼀个压缩包给后台,后台保存后解压读取⾥⾯的⽂件。在这⾥做个记录
1、MultipartFile上传⽂件
⽂件上传有很多⽅法,这⾥推荐⼀种,代码:
@PostMapping(value = "/import", headers = "content-type=multipart/*")
public HttpResponse importSqlLite(@RequestParam("file") MultipartFile file) {
String path = "C:/filePath/";
File newFile = new File(path + OriginalFilename())
return HttpResponse;
}
2、JDK内置操作Zip⽂件
其实,在JDK中已经存在操作ZIP的⼯具类:ZipInputStream。
基本使⽤:例⼦1:
public static Map<String, String> readZipFile(String file) throws Exception {
Map<String, String> resultMap = new HashMap<String, String>();
Charset gbk = Charset.forName("GBK");
ZipFile zf = new ZipFile(file, gbk);  // 此处可以⽤⽆Charset的构造函数,但是即使是设置为GBK也是处理不了中⽂的,后⾯会再说
InputStream in = new BufferedInputStream(new FileInputStream(file));
ZipInputStream zin = new ZipInputStream(in);
ZipEntry ze;
while ((ze = NextEntry()) != null) {
if (ze.isDirectory()) {
} else {
long size = ze.getSize();    // ⽂件的⼤⼩
String name = ze.getName();    // 获取⽂件名称
// 具体对其中每个⽂件的操作和获取信息,可以参考JDK API
if (size > 0) {
InputStream inputStream = zf.getInputStream(ze);    // 拿到⽂件流
// ……    业务逻辑
}
}
}
zin.closeEntry();
return resultMap;
}
例⼦2:
public class FileUtils {
//⽇志
private static final Logger LOGGER = Logger(FileUtils.class);
/**
* 对zip类型的⽂件进⾏解压
*/
public static List<FileModel> unzip(MultipartFile file) {
// 判断⽂件是否为zip⽂件
String filename = OriginalFilename();
if (!dsWith("zip")) {
LOGGER.info("传⼊⽂件格式不是zip⽂件" + filename);
new BusinessException("传⼊⽂件格式错误" + filename);
}
List<FileModel> fileModelList = new ArrayList<FileModel>();
String zipFileName = null;
// 对⽂件进⾏解析
try {
ZipInputStream zipInputStream = new InputStream(), Charset.forName("GBK"));              BufferedInputStream bs = new BufferedInputStream(zipInputStream);
ZipEntry zipEntry;
byte[] bytes = null;
while ((zipEntry = NextEntry()) != null) { // 获取zip包中的每⼀个zip file entry
zipFileName = Name();
压缩包损坏Null(zipFileName, "压缩⽂件中⼦⽂件的名字格式不正确");
FileModel fileModel = new FileModel();
fileModel.setFileName(zipFileName);
bytes = new byte[(int) Size()];
InputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
fileModel.setFileInputstream(byteArrayInputStream);
fileModelList.add(fileModel);
}
} catch (Exception e) {
<("读取部署包⽂件内容失败,请确认部署包格式正确:" + zipFileName, e);
new BusinessException("读取部署包⽂件内容失败,请确认部署包格式正确:" + zipFileName);
}
return fileModelList;
}
}
更多的操作可以参考其他⼈的总结,本⽂的重点在于描述JDK⾃带zip操作API的不便之处,从⽽引出Zip4J。
JDK⾃带ZIP API有个⾮常重⼤的问题:不⽀持ZIP中⽬录中的中⽂。如下异常:
java.lang.IllegalArgumentException: MALFORMED
at java.util.String(Unknown Source)
at java.util.adLOC(Unknown Source)
at java.util.NextEntry(Unknown Source)
at st.adZipFile(BigFileMD5.java:131)
at st.md5.BigFileMD5.checkFileMD5(BigFileMD5.java:42)
at st.TestMain.main(TestMain.java:12)
我的ZIP中⽬录:“Test\Test-01\Te\你好\……”,当然导致该异常的原因不只是中⽂的问题,但是⼤部分情况下都是。对于JDK⾃带的ZIP API还有⼀些其他问题,⽐如操作解压和压缩API接⼝不⽅便(带有密码ZIP)等。当然,⽹上有许多⼈说是已经可以解决中⽂的问题,但是⽐较⿇烦,并不是每次都能够成功,我本地也有尝试过。
在我们的项⽬中,通过不断的⽐较,最终还是选择了ZIP4J。
3、ZIP4J
⽬前最新版本是2.3.1,配置如下:
4、不解压zip⽂件,直接通过InputStream的形式读取其中的⽂件信息
我想结合⼀下我项⽬中需求以及⽹上许多同仁的问题(不解压zip⽂件,直接通过InputStream的形式读取其中的⽂件信息),说⼀个简单的应⽤:不解压ZIP⽂件的前提下,直接利⽤流(InuptStream)形式读取其中的⽂件,并读取⽂件的MD5值。
类似于JDK⾃带ZipInputStream的形式读取zip⽂件,由于ZIP4J的ZipInputStream不具备NextEntry()),所以,在ZIP4J中只能通过FileHeader来进⾏循环。⽽且,JDK⾃带API中获取ZIP其中的⽂件流InputStream时,需要:
ZipFile zf = new ZipFile(file);
InputStream inputStream = zf.getInputStream(ZipEntry);
所以,对应ZIP4J就只能ZipInputStream(该类时InputStream的⼦类)。
具体代码如下:
import java.util.List;
import net.ZipFile;
import net.lingala.zip4j.io.ZipInputStream;
import net.del.FileHeader;
public class ZIP4JUtils {
/**
* @param file
* @throws Exception
*/
public static void readZipFileMD5ByZip4J(String file,String  passwd) throws Exception {
ZipFile zFile = new ZipFile(file);
/
/ 此处最好⽴即设置字符集
zFile.setFileNameCharset("GBK");
if (!zFile.isValidZipFile()) {
return ;
}
if (zFile.isEncrypted()) {
zFile.CharArray());
}