导入zip文件
需求说明
用户导入一个zip压缩文件,文件内有一个Excel文件和一个图片文件夹,要求解压压缩文件,读取Excel表中各个字段的内容,之后根据Excel表中名为“图片名称”的字段在图片文件夹中获取同样名称的图片。
功能点
- 解压zip文件
- 读取Excel文件
- 从文件夹找对应名称文件
代码实现
1.前端代码
<el-upload
class="upload-demo"
ref="uploadTemplate"
name="file"
:on-success="importSuccess"
:action="importUrl"
accept="application/zip"
:limit="2"
:multiple="false"
:file-list="fileTemplateList"
:auto-upload="false"
:on-change="onChange"
>
<el-button slot="trigger" size="small" type="primary"
>选取文件
</el-button>
</el-upload>
代码说明:
使用了ElementUI中的文件上传组件,
- ref属性:为改组件设置一个引用,用于在JavaScript中引用该组件的实例。
- name属性:设置上传文件的参数名称
- :on-success:指定上传成功后的回调函数
- :action:指定上传的url
- accept:限定用户只能选择指定的文件类型,这里的限定并不强制。
- limit:限制用户选择上传文件的个数
multiple="false"
:限制用户只能选择单个文件进行上传。file-list="fileTemplateList"
:指定一个文件列表,用于展示已选择的文件或上传成功的文件。:auto-upload="false"
:设置为false
,禁止自动上传文件,需要手动触发上传操作。-:on-change="onChange"
:指定了文件选择改变时的回调函数,onChange
是一个方法或函数,用于处理文件选择改变后的操作。
2.后端代码
2.1 Controller
/**
* 数据导入
* @title ImportTemplateData
* @description
*
* @param zipfile
* @param id
* @return
*/
@PostMapping("/ImportTemplateData")
public Result<List<String>> ImportTemplateData(@RequestParam("file") MultipartFile zipfile,@RequestParam("id") String id){
return Service.ImportTemplateData(zipfile,id);
}
代码说明:
这里的返回结果根据自己业务定夺。
- 使用
@RequestParam
注解来接受前端上传的文件,其类型为MultipartFile类。第二个id是该业务要求,根据实际需求定夺。
2.2 Service
/**
* 读取导入数据
* @title ImportTemplateData
* @description
*
* @param zipfile
* @param id
* @return
*/
Result<List<String>> ImportTemplateData(@RequestBody MultipartFile zipfile,@RequestParam("id") String id);
}
/**
* 读取导入数据
* @description
*
* @param zipfile
* @param id
* @return
*/
@Override
public Result<List<String>> ImportTemplateData(MultipartFile zipfile,String id,)
{
List<String> resultsList = new ArrayList<String>();
try{
//创建临时文件
File tempFile = File.createTempFile("temp", null);
//将上传文件保存到临时文件中
zipfile.transferTo(tempFile);
//解压缩文件
File unzippedDir = new File("unzipped");
unzipFiles(tempFile,unzippedDir);
//查找并读取Excel文件
File exceFile = findExcelFile(unzippedDir);
if(exceFile == null){
//上传的文件中没有Excel文件,直接返回空;
return null;
}
//读Excel文件
resultsList = readExcel(exceFile,unzippedDir,id);
//删除临时文件和解压后的目录
FileUtil.deleteFile(tempFile);
FileUtil.deleteDir(unzippedDir);
return Result.success(resultsList)
}
catch (Exception e) {
LOGGER.info(e.getMessage());
}
return Result.error;
}
这段业务主要方法有如下几个:
- unzipFiles(tempFile,unzippedDir); 用来解压用户上传的zip文件
- findExcelFile(unzippedDir);用来读取文件夹中Excel文件
- readExcel(exceFile,unzippedDir,id);用来读取Excel文件中的内容。
unzipFile方法
/**
* 解压文件方法
* @title unzipFiles
* @description
* @param zipFile
* @param destDir
* @throws IOException
*/
private void unzipFiles(File zipFile, File destDir) throws IOException {
try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("GBK"))) {
byte[] buffer = new byte[4096];
ZipEntry entry = zipIn.getNextEntry();
while (entry != null) {
String entryName = entry.getName();
File entryFile = new File(destDir, entryName);
if (entry.isDirectory()) {
entryFile.mkdirs();
} else {
extractFile(zipIn, entryFile);
}
zipIn.closeEntry();
entry = zipIn.getNextEntry();
}
}
}
/**
* 提取压缩文件中的文件到目标路径中
* @title extractFile
* @description
*
* @param zipIn
* @param filePath
* @throws IOException
*/
private void extractFile(ZipInputStream zipIn, File destFile) throws IOException {
try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(destFile))) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = zipIn.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
}
代码说明
-
unzipFiles
方法:-
zipFile
参数是要解压的 zip 文件。 -
destDir
参数是解压后的文件保存目录。 -
在方法内部,通过创建
ZipInputStream
对象,并指定使用 GBK 编码读取 zip 文件。 -
定义了一个
buffer
字节数组,用于读取和写入数据。 -
使用
zipIn.getNextEntry()
获取 zip 文件中的下一个条目(文件或目录),如果不存在则表示解压完成。 -
遍历每个条目,获取条目的名称,并创建对应的文件对象
entryFile
。 -
如果条目是目录,则创建目录;否则,调用
extractFile
方法提取文件。 -
关闭当前条目的输入流。
-
获取下一个条目,进行下一轮循环。
注意创建
ZipInputStream
对象时指定的编码格式,这取决与你要上传文件的内容,如果上传内容与指定格式不对会报错“MALFORMED”
-
-
extractFile
方法:zipIn
参数是ZipInputStream
对象,用于读取 zip 文件中的数据。destFile
参数是要保存提取出的文件的目标文件对象。- 在方法内部,通过创建
BufferedOutputStream
对象,并指定目标文件进行输出。 - 定义了一个
buffer
字节数组,用于读取和写入数据。 - 循环读取 zip 文件中的数据,将数据写入目标文件。
- 关闭输出流
这段代码的作用是解压缩给定的 zip 文件,并将其中的文件提取到指定的目录中。unzipFiles
方法负责读取和处理 zip 文件的条目,根据条目类型进行相应的操作。extractFile
方法用于提取单个文件并将其写入目标文件。
findExcelFile方法
/**
* 查找解压后目录下的Excel文件
* @title findExcelFile
* @description
*
* @param dir
* @return
*/
private File findExcelFile(File dir) {
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
File excelFile = findExcelFile(file); // 递归调用,查找子文件夹中的Excel文件
if (excelFile != null) {
return excelFile;
}
} else {
String fileName = file.getName();
if (fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
return file;
}
}
}
}
return null;
}
这个方法利用递归的方式查找文件夹中的Excel文件夹,这里要注意的是由于该需求指定了上传文件的模板,所以可以确保压缩文件中只有一个Excel表,如若其它情况,还需更改代码。
readExcel方法
/**
* 读取Excel文件
* @title readExcel
* @description
*
* @param file
* @return
* @throws IOException
*/
private List<String> readExcel(File file, File unzippedDir,String id) throws IOException {
//收集结果信息
List<List<String>> resultsList = new ArrayList<>();
Workbook workbook = null;
try {
workbook = getWorkbook(file);
Sheet sheet = workbook.getSheetAt(0);
int rowCount = sheet.getLastRowNum() - sheet.getFirstRowNum();
for (int i = 2; i <= rowCount; i++) {//这里是从表的第三行开始遍历;根据实际业务定夺
Row row = sheet.getRow(i);
for (int j = 1; j <= 7; j++) {//这里是遍历第2列到第八列;根据实际业务定夺
Cell cell = row.getCell(j);
//业务操作,对每个字段进行处理
//拿到图片名称后存到一个List集合
//从解压的文件夹中获取存图片的文件夹,然后遍历遍历list集合,再遍历该文件夹的图片。判断图片名称是否与当前图片名称一致,是的话就执行相应操作。
}
}
} catch (Exception e)
{
System.out.println(e);
}
return resultsList;
}
/**
* 获取Excel文件
* @title getWorkbook
* @description
*
* @param file
* @return
* @throws IOException
*/
private static Workbook getWorkbook(File file) throws IOException {
try (InputStream is = new FileInputStream(file)) {
if (file.getName().endsWith(".xls")) {
return new HSSFWorkbook(is);
} else if (file.getName().endsWith(".xlsx")) {
return new XSSFWorkbook(is);
} else {
throw new IllegalArgumentException("Unsupported file format");
}
}
}
代码说明
提供判断传入的文件是哪种类型Excel表返回对应的Workbook类,再遍历有数据的所有行,每行遍历获取列的单元格的数据,进行业务操作。
最后,获取存图片的文件夹和文件操作
/**
* 返回文件夹
* @title findFolder
* @description
*
* @param dir
* @return
*/
private File findFolder(File file) {
if (file.isFile()) {
return null; // 如果输入的是文件而不是文件夹,直接返回null
}
File[] files = file.listFiles();
if (files != null && files.length > 0) {
File lastFolder = null;
for (File f : files) {
if (f.isDirectory()) {
lastFolder = f;
}
}
if (lastFolder != null) {
return findFolder(lastFolder);
}
}
return file;
}
/**
* 处理文件的方法
* @title processFolder
* @description
*
* @param folder
* @param imageName
* @throws Exception
*/
public String processFolder(String imageInfoId, File folder, String imageName) throws Exception {
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile() && ExcelUtils.isImageFile(file) && ExcelUtils.isMatchingName(file,imageName)) {//判断是否为文件以及是图片类型的文件以及文件名是否与传入的图片名称一致
//业务操作
}
}
}
return null;
}
什么的返回文件夹是返回最后一个文件夹,实际应该按照需求来编写,例如返回某个名称的文件夹。