读取/导出带文档密码的表格

前两天做了导出excel还要求打开时输入密码,整理了一下代码,写个工具类。

说明:

  1. excel表格分为2003版本文件名后缀xls和2007版本文件名后缀xlsx,版本不同读写创建文档略有不同
  2. xls加密依赖jxcell.jar,xlsx依赖的poi-ooxml.jar,且两者不能混用否则报错。
  3. xls 自带了写保护功能,但可以绕过密码以只读模式打开文档,只是不能编辑而已。本次的需求是要密码才准查看,所以改用了jxcell.jar
  4. xssfWorkbook当数据超大(1048576行,16384列)时,会面临内存溢出的问题,可以换成SXSSFWorkbook(原理是分批写入磁盘),写法和xssfWorkbook类似。也可以使用阿里的easyexcel(见另外一篇文章)
  5. 工具类功能:加解密xls/xlsx、读取/写入xls/xlsx,数据量很大时候用writeBigDataExcel()

测试类

package ExcelTest;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 测试类
 * 
 * @author yulisao
 * @createDate 2021年4月18日
 */
public class ExcelUtilTest{
	
	public static void main(String[] args) {
		String sheetName = "sheetName";
		String outPath= "C:\\Users\\Administrator\\Desktop\\rr";
		String password = "123456";
		String [] header = {"序号","姓名","手机号"};
		
		List<List<Object>> dataList = new ArrayList<>();
		//用于存储一行数据
		List<Object> list = new ArrayList<Object>();
		//添加第一行第一个元素
		list.add(1);
		//添加第一行第二个元素
		list.add("张三");
		//添加第一行第三个元素
		list.add("15511110000");
		//.....添加第N个元素
		
		//将这一行添加	到大list里面		
		dataList.add(list);
		
		List<Object> list2 = new ArrayList<Object>();
		//添加第一行第一个元素
		list2.add(2);
		//添加第一行第二个元素
		list2.add("李四");
		//添加第一行第三个元素
		list2.add("13200001111");
		dataList.add(list2);
		
		List<Object> list3 = new ArrayList<Object>();
		//添加第一行第一个元素
		list3.add(3);
		//添加第一行第二个元素
		list3.add("王五");
		//添加第一行第三个元素
		list3.add("15799990000");
		dataList.add(list3);
		
		
		System.out.println("-------------excel2003版 test-------------------");
		// 导出xls文件,password为空则不加密文件
		ExcelUtil.writeXlsExcel(sheetName, header, dataList, outPath, password);
		// 加密xls
		//ExcelUtil.entryXlsExcel(outPath + File.separator + sheetName + ".xls",password);
		// 解密xls
		//ExcelUtil.detryXlsExcel(outPath + File.separator + sheetName + ".xls",password);
		
		
		System.out.println("-------------excel2007版 test-------------------");
		// 导出xlsx文件,password为空则不加密文件
		ExcelUtil.writeXlsxExcel(sheetName, header, dataList, outPath, password);
		
		// 加密xlsx文件
		//ExcelUtil.entryXlsxExcel(outPath + File.separator + sheetName + ".xlsx", password);
		// 解密xlsx文件
		//ExcelUtil.detryXlsxExcel(outPath + File.separator + sheetName + ".xlsx", password);
		
		//dataList.clear();
		//dataList = ExcelUtil.readExcel(outPath + File.separator + sheetName + ".xls", 1, password);
		/*
		for (int i = 0; i < dataList.size(); i++) {
			List<Object> list4 = dataList.get(i);
			for (int j = 0; j < list4.size(); j++) {
				System.out.println(list4.get(j));
			}
		}*/
		
		// 超大数据导出
		//ExcelUtil.writeBigDataExcel(sheetName, header, dataList, outPath, password);
    }
}

效果
在这里插入图片描述
在这里插入图片描述

工具类

package ExcelTest;

import java.awt.Color;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.jxcell.CellException;
import com.jxcell.View;

/**
 * 导出excel并加密工具类
 * xls 设置密码依赖jxcell.jar
 * xlsx 设置密码依赖poi-ooxml.jar(部分版本不支持)
 * 两种文件的加解密方法,二者不能混用
 * 
 * @author yulisao
 * @createDate 2021年4月18日
 */
public class ExcelUtil {
	
	private static final String TEMP_XLS_PATH = System.getProperty("java.io.tmpdir") + "temp.xls"; // 系统临时文件
	private static final String TEMP_XLSX_PATH = System.getProperty("java.io.tmpdir") + "temp.xlsx";
	private static final int ROW_LIMT = 10000; // 分次导出单次上限
	
	/**
	 * 导出excel
	 * 
	 * @param sheetName 文件名称
	 * @param header 标题行数组
	 * @param dataList 数据列表
	 * @param outDir 输出目录
	 * @param password 加密密码
	 */
    public static void writeXlsxExcel(String sheetName, String [] header, List<List<Object>> dataList, String outDir, String password) {
        //创建工作薄
        XSSFWorkbook workbook = new XSSFWorkbook();
        //创建表单
        XSSFSheet sheet = workbook.createSheet(sheetName);
        //创建表单样式
        XSSFCellStyle titleStyle = getCellStyle(workbook, true, true);//创建标题样式
        XSSFCellStyle contextStyle = getCellStyle(workbook, true, false);//创建文本样式

        XSSFRow row = sheet.createRow(0);//创建第一行,从0开始
        XSSFCell cell ;//创建列
        
        // 第一行标题行
        for (int i = 0; i < header.length; i++) {
        	 sheet.setColumnWidth(i, 4000);//统一设置列宽
        	 cell = row.createCell(i);//标题行第i列
             cell.setCellValue(header[i]);//标题第i列内容
             cell.setCellStyle(titleStyle);//设置标题样式
        }
        
        //从数据库取数据填充到Excel
        for(int i = 1 ; i < dataList.size() + 1; i++){// 标题行已占据1行,从1开始,
            row=sheet.createRow(i);//创建第i行
            List<Object> data = dataList.get(i-1);
            for (int j = 0; j < data.size(); j++) {
            	 cell=row.createCell(j);//正文第j列
            	 cell.setCellValue(StringUtils.isBlank(data.get(j).toString())?"":data.get(j).toString());//标题第j列的值
                 cell.setCellStyle(contextStyle);//设置样式
			}
        }

        // 文件夹不存在则创建
        String outPath = outDir + File.separator + sheetName + ".xlsx";
        File outFile = new File(outDir);
        if (!outFile.exists()) {
			outFile.mkdir();
		}
        
        //将工作薄写入文件输出流中
        try {
			workbook.write(new FileOutputStream(new File(outPath)));
		} catch (IOException e1) {
			System.out.println("导出文件失败");
			e1.printStackTrace();
			return;
		}
       
        
        // 加密
        if (StringUtils.isNotBlank(password)) {
        	entryXlsxExcel(outPath, password);
		} 
        
    }
    
    /**
     * 读取excel文档(支持xls、xlsx)
     * 
     * @param filePath 文件路径
     * @param begRow 开始读取行(可过滤掉标题行)
     * @param password 文档密码
     * @return
     */
    public static List<List<Object>> readExcel(String filePath, int begRow, String password) {
    	if (begRow < 0) { // 默认第一行开始读取
    		begRow = 0;
		}
    	
    	Workbook wb = getWorkbook(filePath, password); // 读取文档内容
    	Sheet sheet = wb.getSheetAt(0); // 读取第一个文档
      
    	List<List<Object>> dataList = new ArrayList<List<Object>>();
        int numberOfRows = sheet.getPhysicalNumberOfRows(); // 总行数
        for (int i = begRow; i < numberOfRows; i++) { 
            Row row = sheet.getRow(i); // 第i行
            List<Object> list = new ArrayList<Object>();
            int physicalNumberOfCells = row.getPhysicalNumberOfCells(); // 总列数
            for (int j = 0; j < physicalNumberOfCells; j++) {
                //Cell cell = row.getCell(j); // 第i行第j列单元格
                String cell = row.getCell(j).getStringCellValue();
                list.add(cell);
            }
            dataList.add(list);
        }
        
        return dataList;
    }

    /**
     * 创建单元格样式
     * 
     * @param workbook
     * @param border 是否添加边框
     * @param bold 是否加粗
     * @return
     */
    public static XSSFCellStyle getCellStyle(XSSFWorkbook workbook, boolean border, boolean bold){
        XSSFCellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);//文本水平居中显示
        style.setVerticalAlignment(VerticalAlignment.CENTER);//文本竖直居中显示
        style.setWrapText(true);//文本自动换行
  
        // 设置边框
        if (border) {
        	style.setBorderBottom(BorderStyle.THIN);//设置文本边框
            style.setBorderLeft(BorderStyle.THIN);
            style.setBorderRight(BorderStyle.THIN);
            style.setBorderTop(BorderStyle.THIN);
            
            style.setTopBorderColor(new XSSFColor(Color.BLACK));//设置文本边框颜色
            style.setBottomBorderColor(new XSSFColor(Color.BLACK));
            style.setLeftBorderColor(new XSSFColor(Color.BLACK));
            style.setRightBorderColor(new XSSFColor(Color.BLACK));
		}
        
        // 加粗
        if (bold) {
        	XSSFFont titleFont = workbook.createFont();
            titleFont.setBold(true);//加粗
            titleFont.setFontHeight((short)13);//文字尺寸
            titleFont.setFontHeightInPoints((short)13);
            style.setFont(titleFont);
		}

        return style;
    }
    
    /**
     * 加密xlsx文件
     * 
     * @param outPath 文件路径
     * @param password 密码
     */
    public static void entryXlsxExcel(String outPath, String password) {
    	try {
    		POIFSFileSystem fs = new POIFSFileSystem();
    	    EncryptionInfo info = new EncryptionInfo(EncryptionMode.standard);
    	    Encryptor enc = info.getEncryptor();
    	    //设置密码
    	    enc.confirmPassword(password); 
    	    //加密文件
    	    OPCPackage opc = OPCPackage.open(new File(outPath), PackageAccess.READ_WRITE);
    	    OutputStream os = enc.getDataStream(fs);
    	    opc.save(os);
    	    opc.close();

    	    //把加密后的文件写回到流
    	    FileOutputStream fos = new FileOutputStream(outPath);
    	    fs.writeFilesystem(fos);
    	    fos.close();
		} catch (Exception e) {
			System.out.println("加密文件失败");
			e.printStackTrace();
		}
    }
    
    /**
     * 解密xlsx文件
     * 
     * @param outPath 文件路径
     * @param password 密码
     */
    public static void detryXlsxExcel(String outPath, String password) {
    	Workbook wb = null;
        try  {
        	FileInputStream in = new FileInputStream(outPath);
            wb = WorkbookFactory.create(in,password);//设置密码打开
            
            FileOutputStream fileOut = new FileOutputStream(new File(outPath));
            wb.write(fileOut);
            fileOut.close();
        } catch (Exception e) {
        	System.out.println("解密文件失败");
            e.printStackTrace();
        }
       
    }
    
    
    public static void writeXlsExcel(String fileName, String [] header, List<List<Object>> dataList, String outPath, String password) {
		// 创建workbook
		HSSFWorkbook wb = new HSSFWorkbook();

		// 创建sheet
		HSSFSheet sheet = wb.createSheet("sheet1");
		sheet.setDefaultColumnWidth(15); // 设置所有列宽
		//sheet.setColumnWidth(2, 15 * 256); // 第3列设置列宽 15
		
		// 创建行row
		HSSFCellStyle style = wb.createCellStyle();
		FileOutputStream fileOut = null;
		HSSFRow row = sheet.createRow(0);	// 创建第一行: 表头
		
		// 表头的列逐个给值进去
		for (int i = 0; i < header.length; i++) {
			sheet.setColumnWidth(i, 4000);//统一设置列宽
			HSSFCell cell = row.createCell(i);
			cell.setCellValue(header[i]);
			cell.setCellStyle(style);
		}
		
		// 插入数据正文
		int num = 1; // 表头已占一行,所以这里从1开始
		for (List<Object> list : dataList) { // 循环数据行
			row = sheet.createRow(num); // 新建一行
			for (int i = 0; i < list.size(); i++) { // 循环每一行的列
				row.createCell(i).setCellValue(String.valueOf(list.get(i)));// 第i列
			}
			num++;
		}
		
		// 输出
		String path = outPath + File.separator + fileName + ".xls";
		try {
			fileOut = new FileOutputStream(new File(path));
			wb.write(fileOut);
			fileOut.close();
		} catch (IOException e) {
			System.out.println("e1=" + e);
		} finally {
			try {
				fileOut.close();
			} catch (IOException e2) {
				System.out.println("e2=" + e2);
			}
		}
		
		if (StringUtils.isNotBlank(password)) {
			entryXlsExcel(path, password);
		}
		
	}


    
    /**
     * 加密xls文件
     * 
     * @param outPath 文件路径
     * @param password 密码
     */
    public static void entryXlsExcel(String outPath, String password) {
    	View view = new View();
        try {
            // 读取Excel文档
            view.read(outPath);
            // 设置文档打开密码
            view.write(outPath, password);
        } catch (CellException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 解密xls文件
     * 
     * @param outPath 文件路径
     * @param password 密码
     */
    public static void detryXlsExcel(String outPath, String password) {
		View view = new View();
		try {
			//尝试用错误的打开密码读文件
			view.read(outPath, password);
			view.write(TEMP_XLS_PATH); // 先写入临时文件夹,再移动回来
			File outFile = new File(outPath);
			outFile.delete(); // 调用此方法前outPath不要被输入输出流及其他程序占用,否则删除不成功
			File tempFile = new File(TEMP_XLS_PATH);
			tempFile.renameTo(outFile); // 原文件未删除,则无法移回同名文件
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}
    
    /**
     * 获取excel内容
     * 
     * @param filePath 路径
     * @param passWord 密码
     * @return
     */
    public static Workbook getWorkbook(String filePath, String passWord){
        Workbook workbook  = null;
        try {
        	
            if (StringUtils.endsWithIgnoreCase(filePath,".xls")){
            	if (StringUtils.isNotBlank(passWord)) {
            		detryXlsExcel(filePath, passWord);
            	} 
            	POIFSFileSystem pfs = new POIFSFileSystem(new FileInputStream(new File(filePath))); // 2003版本
                workbook = new HSSFWorkbook(pfs,true);	
                
            }else if (StringUtils.endsWithIgnoreCase(filePath,".xlsx")){
            	FileInputStream inputStream = new FileInputStream(new File(filePath));
            	if (StringUtils.isBlank(passWord)) {
            		workbook  = new XSSFWorkbook(inputStream); // 2007版本
				} else {
					workbook = WorkbookFactory.create(inputStream, passWord);//设置密码打开
				}
            }
        } catch (IOException | EncryptedDocumentException
				| InvalidFormatException e) {
            e.printStackTrace();
        }
        return workbook;
    }
    
    /**
	 * 导出excel(适用数据量超大,大于10w行时候)
	 * 
	 * @param sheetName 文件名称
	 * @param header 标题行数组
	 * @param dataList 数据列表
	 * @param outDir 输出目录
	 * @param password 加密密码
	 */
    public static void writeBigDataExcel(String sheetName, String [] header, List<List<Object>> dataList, String outDir, String password) {
		
		// 文件夹不存在则创建
		String outPath = outDir + File.separator + sheetName + ".xlsx";
		File outFile = new File(outDir);
		if (!outFile.exists()) {
			outFile.mkdir();
		}
		
		
		// 创建XSSFWorkbook输出
		BufferedOutputStream outputStream = null;
		XSSFWorkbook workbook = null;
		try  {
			outputStream = new BufferedOutputStream(new FileOutputStream(new File(outPath)));
			workbook = new XSSFWorkbook();
			workbook.createSheet(sheetName);
			workbook.write(outputStream);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(outputStream!=null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		SXSSFWorkbook sxssfWorkbook = null;
		try {
			// 加载ROW_LIMT条到内存,其他输出到磁盘
			sxssfWorkbook = new SXSSFWorkbook(workbook, ROW_LIMT);
			
			// 获取第一个Sheet页
			SXSSFSheet sheet = sxssfWorkbook.getSheetAt(0);
			
			// 创建表头行
			SXSSFRow row = sheet.createRow(0);
			SXSSFCell cell ;//创建列
			// 设置行样式
			XSSFCellStyle titleStyle = getCellStyle(workbook, true, true);//创建标题样式
			XSSFCellStyle contextStyle = getCellStyle(workbook, true, false);//创建文本样式
			
			// 表头的列逐个给值进去
			for (int i = 0; i < header.length; i++) {
				sheet.setColumnWidth(i, 4000);// 统一设置列宽
				cell = row.createCell(i);// 标题行第i列
				cell.setCellValue(header[i]);// 标题第i列内容
				cell.setCellStyle(titleStyle);// 设置标题样式
			}

			// 写入数据
			for (int i = 1; i < dataList.size() + 1; i++) {// 标题行已占据1行,从1开始,
				row = sheet.createRow(i);// 创建第i行
				List<Object> data = dataList.get(i - 1);
				for (int j = 0; j < data.size(); j++) {
					 cell=row.createCell(j);//正文第j列
	            	 cell.setCellValue(StringUtils.isBlank(data.get(j).toString())?"":data.get(j).toString());//标题第j列的值
	                 cell.setCellStyle(contextStyle);//设置样式
				}
			}
			
			

			outputStream = new BufferedOutputStream(new FileOutputStream(outPath)); // 读取文件
			sxssfWorkbook.write(outputStream); // 写入
			outputStream.flush();
			sxssfWorkbook.dispose();// 释放资源
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		// 加密
        if (StringUtils.isNotBlank(password)) {
        	entryXlsxExcel(outPath, password);
		} 
	}
    
 }

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值