java如何替換word/doc文件中的內(nèi)容
docx格式的文件本質(zhì)上是一個XML文件,只要用占位符在指定的地方標(biāo)記,然后替換掉標(biāo)記出的內(nèi)容,就能達到我們的目的
封裝成工具類
import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** * Author ht * Date: 2023-06-30 */ //替換.docx文件的工具類 public class DocxUtil { // 保存隨機生的解壓出.docx文件的保存目錄 private static final String cachePath = System.getProperty("user.dir") + File.separator + UUID.randomUUID().toString().replaceAll("-", ""); // 保存模板文件的輸入流和模板壓縮輸入流 private static final List<InputStream> iss = new ArrayList<>(); // 替換docx文件中的內(nèi)容 public static void compile(FileInputStream is, Map<String, String> data, FileOutputStream os) throws IOException { // 獲取模板保存的目錄 Path path = Paths.get(cachePath); // 如果不存在或者當(dāng)前的模板輸入流不在輸入流集合中就解壓模板 if (!Files.exists(path) || !iss.contains(is)) { // 解壓docx文件 unDocx(is); } // 替換document.xml的內(nèi)容 replaceXmlContent(data); // 把解壓的文件重新壓縮成docx文件 buildDocx(os); } // 解壓docx文件 private static void unDocx(FileInputStream template) throws IOException { // 解壓出來文件保存的目錄 File cacheDir = new File(cachePath); if (!cacheDir.exists()) { // 不存在就先創(chuàng)建該文件夾 Files.createDirectory(Paths.get(cacheDir.getPath())); } // 創(chuàng)建壓縮包輸入流 ZipInputStream zis = new ZipInputStream(template); // 把需要關(guān)閉的模板輸入流存到集合中 iss.add(template); iss.add(zis); // 獲取首個壓縮文件中的文件 ZipEntry entry = zis.getNextEntry(); // 內(nèi)容緩沖區(qū) byte[] buff = new byte[1024 * 10]; // 循環(huán)獲取壓縮包中的壓縮文件 while (entry != null) { // 判斷當(dāng)前的壓縮文件是文件夾還是文件 if (entry.isDirectory()) { // 如果是文件夾就要創(chuàng)建對應(yīng)的文件夾 Path tempDir = Paths.get(cacheDir.getPath() + File.separator + entry.getName()); // 不存在就創(chuàng)建 if (!Files.exists(tempDir)) { Files.createDirectory(tempDir); } } else { // 如果是文件就創(chuàng)建文件寫入內(nèi)容 File file = new File(cacheDir, entry.getName()); // 創(chuàng)建文件的輸出流 FileOutputStream fos = new FileOutputStream(file); // 寫入內(nèi)容到輸出流 int len; while ((len = zis.read(buff)) != -1) { fos.write(buff, 0, len); } // zis.transferTo(fos); // jdk9及更高版本可以用這個 // 關(guān)閉當(dāng)前文件的輸出流 fos.close(); } // 獲取下一個壓縮文件 entry = zis.getNextEntry(); } System.out.println("===== 模板docx文件解壓完成 ====="); } // 替換document.xml的內(nèi)容 private static void replaceXmlContent(Map<String, String> data) throws IOException { // document.xml的位置 String documentXmlPath = cachePath + File.separator + "word" + File.separator + "document.xml"; // 獲取document.xml文件的輸入流 FileInputStream fis = new FileInputStream(documentXmlPath); // 讀取xml中的內(nèi)容 byte[] buff = new byte[fis.available()]; fis.read(buff); // 獲取xml文件中的內(nèi)容 String content = new String(buff); // 拿到Map集合中的數(shù)據(jù)和值,替換掉對應(yīng)位置的內(nèi)容 for (String key : data.keySet()) { String value = data.get(key); System.out.println("替換 [ {{" + key + "}} ] 為 => [ " + value + " ]"); content = content.replaceAll("\\{\\{" + key + "\\}\\}", value); } // 把替換好的內(nèi)容寫入原來的document.xml文件中 FileOutputStream fos = new FileOutputStream(documentXmlPath); // 寫入內(nèi)容 fos.write(content.getBytes(StandardCharsets.UTF_8)); // 關(guān)閉流 fos.close(); fis.close(); System.out.println("===== 替換完成 ====="); } // 把替換好document.xml內(nèi)容的文件夾重新壓縮成docx文件 private static void buildDocx(FileOutputStream template) throws IOException { // 創(chuàng)建壓縮文件輸出流 ZipOutputStream zos = new ZipOutputStream(new DataOutputStream(template)); // 獲取要壓縮文件的路徑 Path path = Paths.get(cachePath); // 遍歷當(dāng)前壓縮文件路徑下的所有文件 Files.walkFileTree(path, new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // 獲取當(dāng)前文件的父目錄的名字 String parent = file.getParent().getFileName().toString(); // 壓縮文件的名字 String zipFileName; // 如果父目錄是根目錄名字就是當(dāng)前的名字否則就是夫目錄加上當(dāng)前的名字 if (parent.equals(path.toFile().getName())) { zipFileName = file.toFile().getName(); } else { // 如果父目錄的夫目錄是word就需要word+當(dāng)前文件的父目錄+當(dāng)前文件的名字 if ("word".equals(file.getParent().getParent().toFile().getName())) { zipFileName = "word" + File.separator + parent + File.separator + file.toFile().getName(); } else { // 如果不是就是當(dāng)前文件的父目錄+當(dāng)前文件的名字 zipFileName = parent + File.separator + file.toFile().getName(); } } // 把文件添加到壓縮包中 zos.putNextEntry(new ZipEntry(zipFileName)); // 獲取當(dāng)前文件的輸入流 DataInputStream zis = new DataInputStream(new FileInputStream(file.toFile())); // 寫入內(nèi)容到當(dāng)前的壓縮文件 int len; byte[] buff = new byte[1024 * 10]; while ((len = zis.read(buff)) != -1) { zos.write(buff, 0, len); } zis.close(); // zis.transferTo(zos); // jdk9及更高版本可以用這個 return super.visitFile(file, attrs); } }); // 關(guān)閉流 zos.close(); template.close(); System.out.println("===== 把解壓的文件重新壓縮成.docx ===="); } // 關(guān)閉模板輸入流和清除緩存文件 public static void closeTemplateAndClearCache() { // 關(guān)閉集合中的所有流 for (InputStream inputStream : iss) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } // 刪除緩存文件 deleteCache(new File(cachePath)); System.out.println("===== 關(guān)閉了模板,清理了緩存 ====="); } // 刪除不用的緩存解壓文件目錄 private static void deleteCache(File cachePath) { // 先刪文件夾里面的文件 for (File file : Objects.requireNonNull(cachePath.listFiles())) { // 是文件夾就遞歸調(diào)用 if (file.isDirectory()) { deleteCache(file); } else { // 是文件就直接刪 file.delete(); } } // 刪掉自己 cachePath.delete(); } }
使用
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * Author ht * Date: 2023-06-30 */ public class App { public static void main(String[] args) throws IOException { // 填充的數(shù)據(jù) Map<String, String> data = new HashMap<>(); data.put("name", "hello world"); data.put("time", "2022年10月1日"); // 模板輸入流 FileInputStream is = new FileInputStream("src/main/resources/one.docx"); // 模板輸出流 FileOutputStream os = new FileOutputStream("src/main/resources/test1.docx"); FileOutputStream os1 = new FileOutputStream("src/main/resources/test2.docx"); // 生成模板 DocxUtil.compile(is, data, os); DocxUtil.compile(is, data, os1); // 關(guān)閉模板輸入流和清除緩存文件 DocxUtil.closeTemplateAndClearCache(); } }
記錄一些代碼和問題處理方式,需要參考的請謹(jǐn)慎。
到此這篇關(guān)于java如何替換word/doc文件中的內(nèi)容的文章就介紹到這了,更多相關(guān)java替換文件內(nèi)容內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis實現(xiàn)兩種查詢樹形數(shù)據(jù)的方法詳解(嵌套結(jié)果集和遞歸查詢)
樹形結(jié)構(gòu)數(shù)據(jù)在開發(fā)中十分常見,比如:菜單數(shù)、組織樹, 利用 MyBatis 提供嵌套查詢功能可以很方便地實現(xiàn)這個功能需求。本文主要介紹了兩種方法,感興趣的可以了解一下2021-09-09Java創(chuàng)建線程的七種方法總結(jié)(全網(wǎng)最全面)
線程是Java中的基本執(zhí)行單元,它允許程序在同一時間執(zhí)行多個任務(wù),下面這篇文章主要給大家總結(jié)介紹了關(guān)于Java創(chuàng)建線程的七種方法,文中通過實例代碼將這七種方法介紹的非常詳細,需要的朋友可以參考下2023-05-05Java調(diào)用基于Ollama本地大模型的實現(xiàn)
本文主要介紹了Java調(diào)用基于Ollama本地大模型的實現(xiàn),實現(xiàn)文本生成、問答、文本分類等功能,開發(fā)者可以輕松配置和調(diào)用模型,具有一定的參考價值,感興趣的可以了解一下2025-03-03淺談Java?abstract關(guān)鍵字不能和哪些關(guān)鍵字共存
本文主要介紹了Java?abstract關(guān)鍵字不能和哪些關(guān)鍵字共存,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-10-10