1. 程式人生 > >java操作word文件通用工具類

java操作word文件通用工具類

package cn.com.test.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.apache.log4j.Logger;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;

/**
* word工具類
* @author:  Rodge
* @time:      2017年12月24日 上午09:01:47
* @version:V1.0.0
*/
public final class WordUtil {

	/** 日誌物件 **/
	private static final Logger LOGGER = Logger.getLogger(WordUtil.class);
	
	/** 臨時目錄 **/
	private static final String TEMP_PATH = "temp/";

	/** 臨時docx檔案 **/
	private static final String TEMP_FILE_DOCX = "temp.docx";
	
	/** utf-8字元編碼 **/
	private static final String CHARSET_UTF8 = "UTF-8";
	
	/** 緩衝區大小1M **/
	private static final int BUFFER_SIZE = 1024 * 1024;
	
	/** 私有構造器 **/
	private WordUtil() { }
	
	/**
	 * 根據模板生成新的word2003文件
	 * @param modelPath 模板存放路徑,例如:/template/word/word2003.xml
	 * @param savePath 新文件儲存路徑,例如:D:/word/word2003.doc
	 * @param map 寫入文件的資料
	 */
	public static void createWord2003(String modelPath, String savePath, Map<String, Object> map) {
		Template template = getTemplate(modelPath);
		if (template != null) {
			File file = createFile(savePath);
			try (Writer out = new OutputStreamWriter(new FileOutputStream(file))) {
				template.process(map, out);
			} catch (TemplateException | IOException e) {
				LOGGER.error("生成word2003文件失敗", e);
			}
		}
	}
	
	/**
	 * 根據模板生成新的word2003文件,以位元組陣列返回
	 * @param modelPath 模板存放路徑,例如:/template/word/word2003.xml
	 * @param map 寫入文件的資料
	 * @return byte[] 位元組陣列
	 */
	public static byte[] createWord2003(String modelPath, Map<String, Object> map) {
		Template template = getTemplate(modelPath);
		if (template != null) {
			return createNewTemp(template, map);
		}
		return new byte[0];
	}
	
	/**
	 * 根據模板生成新的word2007文件
	 * @param modelPathXml 模板存放路徑,例如:/template/word/word2007.xml
	 * @param modelPathDocx 模板原文件,例如:/template/word/word2007.docx
	 * @param savePath 新文件儲存路徑,例如:D:/word/word2007.docx
	 * @param map 寫入文件的資料
	 */
	public static void createWord2007(String modelPathXml, String modelPathDocx, String savePath, Map<String, Object> map) {
		ZipFile zipFile = null;
		ZipOutputStream zipOut = null;
		try {
			Template template = getTemplate(modelPathXml);
		    byte[] bytes = createNewTemp(template, map);
		    outTempFile(modelPathDocx); // 寫出臨時檔案(因Linux環境無法直接讀取modelPathDocx路徑)
		    zipFile = new ZipFile(new File(TEMP_PATH + TEMP_FILE_DOCX)); // 讀取臨時檔案          
            Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();  
            zipOut = new ZipOutputStream(new FileOutputStream(savePath));  
            int len = -1;  
            byte[] buffer = new byte[BUFFER_SIZE]; 
            while (zipEntrys.hasMoreElements()) { 
            	ZipEntry entry = zipEntrys.nextElement();  
                zipOut.putNextEntry(new ZipEntry(entry.toString()));  
                if ("word/document.xml".equals(entry.toString())) {  
                	zipOut.write(bytes);
                } else {  
                	try (InputStream is = zipFile.getInputStream(entry)) {
                		while ((len = is.read(buffer)) != -1) {  
                			zipOut.write(buffer, 0, len);  
                		}  
					} catch (IOException e) {
						LOGGER.error("操作流失敗", e);
					}
                }
            }
		} catch (IOException e) {
			LOGGER.error("生成word2007文件失敗", e);
		} finally {
			if (zipFile != null) {
				try {
					zipFile.close();
				} catch (IOException e) {
					LOGGER.error("關閉流失敗", e);
				}
			}
			if (zipOut != null) {
				try {
					zipOut.close();
				} catch (IOException e) {
					LOGGER.error("關閉流失敗", e);
				}
			}
			deleteFiles(TEMP_PATH); // 刪除臨時檔案
		}
	}
	
	/**
	 * 根據模板生成新的word2007文件,以位元組陣列返回
	 * @param modelPathXml 模板存放路徑,例如:/template/word/word2007.xml
	 * @param modelPathDocx 模板原文件,例如:/template/word/word2007.docx
	 * @param map 寫入文件的資料
	 * @return byte[]
	 */
	public static byte[] createWord2007(String modelPathXml, String modelPathDocx, Map<String, Object> map) {
		ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
		ZipFile zipFile = null;
		ZipOutputStream zipOut = null;
		try {
			Template template = getTemplate(modelPathXml);
			byte[] bytes = createNewTemp(template, map);
			outTempFile(modelPathDocx); // 寫出臨時檔案(因Linux環境無法直接讀取modelPathDocx路徑)
			zipFile = new ZipFile(new File(TEMP_PATH + TEMP_FILE_DOCX)); // 讀取臨時檔案           
			Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();  
			zipOut = new ZipOutputStream(byteStream);  
			int len = -1;  
			byte[] buffer = new byte[BUFFER_SIZE]; 
			while (zipEntrys.hasMoreElements()) { 
				ZipEntry entry = zipEntrys.nextElement();  
				zipOut.putNextEntry(new ZipEntry(entry.toString()));  
				if ("word/document.xml".equals(entry.toString())) {  
					zipOut.write(bytes);
				} else {  
					try (InputStream is = zipFile.getInputStream(entry)) {
						while ((len = is.read(buffer)) != -1) {  
							zipOut.write(buffer, 0, len);  
						}  
					} catch (IOException e) {
						LOGGER.error("操作流失敗", e);
					}
				}
			}
		} catch (IOException e) {
			LOGGER.error("生成word2007文件失敗", e);
		} finally {
			if (zipFile != null) {
				try {
					zipFile.close();
				} catch (IOException e) {
					LOGGER.error("關閉流失敗", e);
				}
			}
			if (zipOut != null) {
				try {
					zipOut.close();
				} catch (IOException e) {
					LOGGER.error("關閉流失敗", e);
				}
			}
			deleteFiles(TEMP_PATH); // 刪除臨時檔案
		}
		return byteStream.toByteArray();
	}
	
	/**
	 * 寫出臨時檔案
	 * @param modelPathDocx word2007原文件存放路徑
	 */
	private static void outTempFile(String modelPathDocx) {
		InputStream input = WordUtil.class.getClassLoader().getResourceAsStream(modelPathDocx);
		if (input != null) {
			try (FileOutputStream fos = new FileOutputStream(createFile(TEMP_PATH + TEMP_FILE_DOCX))) {
				int len = -1;  
				byte[] buffer = new byte[BUFFER_SIZE];
				while ((len = input.read(buffer)) != -1) {  
					fos.write(buffer, 0, len);  
				}
			} catch (IOException e) {
				LOGGER.error("寫出臨時檔案失敗", e);
			} finally {
				try {
					input.close();
				} catch (IOException e) {
					LOGGER.error("關閉輸入流失敗", e);
				}
			}
		}
	}
	
	/**
     * 刪除該目錄下所有檔案
     * @param filePath 檔案目錄路徑,如:d:/test/
     */
    public static boolean deleteFiles(String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
				for (File f : files) {
					if (f.isFile() && f.delete()) {
						LOGGER.info("刪除" + f.getName() + "檔案成功");
					}
				}
				return true;
			}
        }
        return false;
    }

    /**
     * 刪除單個檔案
     * @param filePath 檔案目錄路徑,如:d:/test/
     * @param fileName 檔名稱,如:110.doc
     */
    public static boolean deleteFile(String filePath, String fileName) {
        File file = new File(filePath);
        if (file.exists()) {
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
				for (File f : files) {
					if (f.isFile() && f.getName().equals(fileName)) {
						return f.delete();
					}
				}
			}
        }
        return false;
    }
	
	/**
	 * 寫入資料,生成新的模板檔案以位元組陣列返回
	 * @param template 模板物件
	 * @param map 寫入文件的資料
	 * @return byte[]
	 */
	private static byte[] createNewTemp(Template template, Map<String, Object> map) {
		ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
		try (Writer out = new OutputStreamWriter(byteStream)) {
			template.process(map, out);
		} catch (TemplateException | IOException e) {
			LOGGER.error("生成新模板檔案失敗", e);
		}
		return byteStream.toByteArray();
	}
	
	/**
	 * 建立檔案物件
	 * @param filePath 檔案路徑,例如:temp/test.doc
	 * @return File
	 */
	private static File createFile(String filePath) {
		File file = null;
		try {
			// 建立檔案目錄
			file = new File(filePath.substring(0, filePath.lastIndexOf('/')));
			if (!file.exists()) {
				file.mkdirs();
			}		
			// 建立檔案物件
			file = new File(filePath);
			if (!file.exists() && file.createNewFile()) {
				LOGGER.info("建立檔案物件成功");
			}
		} catch (IOException e) {
			LOGGER.error("建立檔案物件失敗", e);
		}
		return file;
	}
	
	/**
	 * 獲取模板物件
	 * @param modelPath 模板存放路徑
	 * @return
	 */
	private static Template getTemplate(String modelPath) {
		Template template = null;
		try {
			Configuration configuration = new Configuration(Configuration.VERSION_2_3_25);
			configuration.setEncoding(Locale.getDefault(), CHARSET_UTF8);
			configuration.setClassForTemplateLoading(WordUtil.class, modelPath.substring(0, modelPath.lastIndexOf('/')));
			template = configuration.getTemplate(modelPath.substring(modelPath.lastIndexOf('/') + 1));
		} catch (TemplateNotFoundException | MalformedTemplateNameException | ParseException e) {
			LOGGER.error("讀取模板失敗", e);
		} catch (IOException e) {
			LOGGER.error("建立模板物件失敗", e);
		}
		return template;
	}
	
}