java导出文件大数据量一种处理思路:多文件压缩导出; 1,查询的时候分页查询 确定总的文件个数:totalExcel; 总条数:count; 单个excel设定的行数:SINGLE_EXCEL_NUM; totalExcel=count/SINGLE_EXCEL_NUM + (count % SINGLE_EXCEL_NUM != 0 ? 1 : 0); 2,for 循环 分多次查询数据,每查询一次数据 就创建一个excel文件到本地目录;for循环中使用threadPool 多线程; 3,等待多线程执行完,压缩excel生成zip文件并导出。
下面是我的例子:
//文件导出
@RequestMapping("/exportExcel")
public Object exportExcel(HttpServletRequest request, HttpServletResponse response){
Long start=System.currentTimeMillis();
try {
String path = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX).getAbsolutePath().toString();
System.out.println("path:"+path);
//String path = "";
String templetePath = path + "/templates/test_export_template.xls";//模板文件
String exportType = " test";//临时文件夹
String tempExcelName = "test_export_" + new Date().getTime();
Map<String, Object> mapParam = new HashMap<>();//查询参数
//mapParam.put("", "");
int totalCount = 50000;//查询到的总数据
final int SINGLE_EXCEL_NUM = 10000;//单个excel设定的行数
if (totalCount > SINGLE_EXCEL_NUM) {
ExecutorService threadPool = Executors.newCachedThreadPool();//创建线程池
int excelCount = totalCount / SINGLE_EXCEL_NUM + (totalCount % SINGLE_EXCEL_NUM != 0 ? 1 : 0);
CountDownLatch latch = new CountDownLatch(excelCount);
for (int i = 1; i <= excelCount; i++) {
final int index = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
//查询并生成一 个exce1存入磁盘
int pageNo=index;
int pageSize=SINGLE_EXCEL_NUM;
List<Map<String,Object>> resuList = queryDataList(pageNo,pageSize); //查询数据
Map downMap = new HashMap();
downMap.put("list", resuList);
ExcelUtils.createOneExcel(downMap,templetePath ,exportType ,tempExcelName ,index);
latch.countDown();
}
});
}
latch.await();
//压缩excel文件并导出
ExcelUtils.createZipExport(request, response, exportType ,tempExcelName);
System.out.println("导出耗时:"+(System.currentTimeMillis() - start));
}else{
//直接导出excel
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
//测试数据
public List<Map<String,Object>> queryDataList(int pageNo,int pageSize){
List<Map<String,Object>> dataList=new ArrayList<>();
for (int i = 1; i <= pageSize; i++) {
int id = i+(pageNo-1)*pageSize;
Map<String,Object> data=new HashMap<>();
data.put("id", id);
data.put("name","测试数据-"+id);
data.put("code", "test_"+new Date().getTime());
data.put("time", new SimpleDateFormat("yyyyMMdd hh:mm:ss").format(new Date()));
data.put("status", "已成功");
dataList.add(data);
}
return dataList;
}
其中用到的两个工具类,ExcelUtils:
import net.sf.jxls.exception.ParsePropertyException;
import net.sf.jxls.transformer.XLSTransformer;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Map;
public class ExcelUtils{
private static Logger log= LoggerFactory.getLogger(ExcelUtils.class);
/**
* 生成一个Excel存放到本地路径
* @param downMap 要导出的数据
* @param templetePath 模板文件路径 这个jxls导出Excel需要
* @param exportType 新增的临时文件夹名称
* @param tempExcelName 导出文件名称
* @param index 第几个文件
*/
public static void createOneExcel(Map downMap,String templetePath,String exportType,String tempExcelName,int index) {
//文件存放路径 getFileRootPath()/exportType/tempExcelName
String excelFold= FileUtil.getFileRootPath()+File.separator +exportType+File.separator +tempExcelName;
//如果路径不存在就创建
File file=new File(excelFold);
if(!file.exists()){
file.mkdirs();
}
//生成的新文件
tempExcelName=excelFold+File.separator+tempExcelName+"_"+index+".xls";
log.info("tempExcelName:"+tempExcelName);
//创建excel文件 方式可以使用poi,easyExcel,jxls等
//这里使用jxls
// 创建XLSTransformer对象
XLSTransformer transformer = new XLSTransformer();
try {
// 生成Excel文件
transformer.transformXLS(templetePath, downMap, tempExcelName);
} catch (ParsePropertyException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
}
}
/**压缩打包所有Excel文件并导出
* @param request
* @param response
* @param exportType
* @param tempExcelName
*/
public static void createZipExport(HttpServletRequest request,
HttpServletResponse response,
String exportType,
final String tempExcelName) throws Exception{
// zip文件所在路径
String zipFold = FileUtil.getFileRootPath() + File.separator + exportType;
// excel文件路径
String excelFold = zipFold+ File.separator+ tempExcelName;
// 生成zip文件
final String zipFileName = tempExcelName +".zip";
FileUtil.createZipFile(excelFold, zipFold, zipFileName);
// 创建导出输入流
InputStream is = null;
try{
is = new FileInputStream(new File(zipFold + File.separator + zipFileName));
} catch(IOException e){
e.printStackTrace();
}
BufferedInputStream bis = new BufferedInputStream(is);
// ServletOutputStream out = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
// 解决设置名称时的乱码问题
String zipName = zipFileName;
// 设置response参数,可以打开下载页面
response.reset();
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + zipName);
byte[] buff = new byte[2048];
int bytesRead;
// Simple read/write loop.
while ((bytesRead = bis.read(buff, 0, buff.length)) != -1 ) {
bos.write(buff, 0, bytesRead);
}
bis.close();
bos.close();
// 删除用来临时保存Excel的文件夹及zip文件
FileUtil.deleteDir(new File(zipFold));
}
}
FileUtil代码如下:
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class FileUtil {
/**
* @param sourceFilePath 待压缩文件(夹)路径
* @param targetPath 压缩文件所在目录
* @param zipFileName 压缩后的文件名称{.zip结尾}
* @return
* @Description: 创建zip文件
*/
public static boolean createZipFile(String sourceFilePath, String targetPath, String zipFileName){
boolean flag = false;
FileOutputStream fos = null;
ZipOutputStream zos = null;
// 要压缩的文件资源
File sourceFile = new File(sourceFilePath);
// zip文件存放路径
String zipPath = "";
if(null != targetPath && !"".equals(targetPath)){
zipPath = targetPath + File.separator + zipFileName;
} else {
zipPath = new File(sourceFilePath).getParent() + File.separator + zipFileName;
}
if (sourceFile.exists() == false) {
System.out.println("待压缩的文件目录:" + sourceFilePath + "不存在.");
return flag;
}
try {
File zipFile = new File(zipPath);
if (zipFile.exists()) {
//log.error(zipPath + "目录下存在名字为:" + zipFileName + ".zip" + "打包文件.");
} else {
File[] sourceFiles = sourceFile.listFiles();
if (null == sourceFiles || sourceFiles.length < 1) {
//log.error("待压缩的文件目录:" + sourceFilePath + "里面不存在文件,无需压缩.");
} else {
fos = new FileOutputStream(zipPath);
zos = new ZipOutputStream(new BufferedOutputStream(fos));
// 生成压缩文件
writeZip(sourceFile, "", zos);
flag = true;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
//关闭流
try {
if (null != zos) {
zos.close();
}
if (null != fos){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return flag;
}
/**
* @param file
* @param parentPath
* @param zos
* @Description:
*/
private static void writeZip(File file, String parentPath, ZipOutputStream zos) {
if (file.exists()) {
// 处理文件夹
if (file.isDirectory()) {
parentPath += file.getName() + File.separator;
File[] files = file.listFiles();
if (files.length != 0) {
for (File f : files) {
// 递归调用
writeZip(f, parentPath, zos);
}
} else {
// 空目录则创建当前目录的ZipEntry
try {
zos.putNextEntry(new ZipEntry(parentPath));
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
ZipEntry ze = new ZipEntry(parentPath + file.getName());
zos.putNextEntry(ze);
byte[] content = new byte[1024];
int len;
while ((len = fis.read(content)) != -1) {
zos.write(content, 0, len);
zos.flush();
}
} catch (FileNotFoundException e) {
// log.error("创建ZIP文件失败", e);
} catch (IOException e) {
//log.error("创建ZIP文件失败", e);
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
// log.error("创建ZIP文件失败", e);
}
}
}
}
}
// deleteDir()删除目录 以及目录下的文件
public static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir
(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
if(dir.delete()) {
System.out.println("目录已被删除!");
return true;
} else {
System.out.println("目录删除失败!");
return false;
}
}
//获取文件操作路径(已存在)
public static String getFileRootPath(){
return "D:\\temp";
}
}
到这里代码就可以了,下面是我的excel导出模板,test_export_template.xls
接下来就是测试了,如果觉得jxls模板导出Excel速度太慢的话,建议导出Excel文件那块换成其他好点的工具,比如阿里的easyExcel。