通过java将 word(.doc) 转 md

说明:使用的jdk8的版本

1、添加相关依赖

复制代码
        <!-- Apache POI 处理Word文档 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>4.1.2</version>
        </dependency>

2、实现代码

java 复制代码
// 转换 .doc 格式文件
    public void convertDoc(String inputPath, String outputPath) throws IOException {
        try (HWPFDocument document = new HWPFDocument(new FileInputStream(inputPath));
             FileWriter writer = new FileWriter(outputPath)) {

            Range range = document.getRange();
            for (int i = 0; i < range.numParagraphs(); i++) {
                Paragraph para = range.getParagraph(i);
                String text = para.text().trim();
                if (text.isEmpty()) continue;

                // 处理标题
                String mdText = processDocHeading(para, text);
                if (mdText != null) {
                    writer.write(mdText + "\n\n");
                    continue;
                }

                // 处理列表
                mdText = processDocList(para, text);
                if (mdText != null) {
                    writer.write(mdText + "\n\n");
                    continue;
                }

                // 普通段落 自定义过滤条件
                if (!text.contains("页 共")){
                    writer.write(text + "\n\n");
                }
            }
        }
    }

    // 处理 .doc 标题
    private String processDocHeading(Paragraph para, String text) {
        int styleIndex = para.getStyleIndex();
        // 标题样式索引通常为 0-5 对应 1-6 级标题
        if (styleIndex >= 0 && styleIndex <= 5) {
            if (text.contains("?")){//自定义过滤条件
                return repeat("#", styleIndex + 1) + " " + text;//styleIndex + 1表示从标题1开始
            }
        }
        return null;
    }

    // 处理 .doc 列表
    private String processDocList(Paragraph para, String text) {
        // 兼容处理列表判断,避免使用可能不存在的方法
        try {
            // 通过反射检查是否有 getListFormat 方法
            Object listFormat = para.getClass().getMethod("getListFormat").invoke(para);
            if (listFormat != null) {
                // 检查是否有列表编号
                Object listNumber = listFormat.getClass().getMethod("getListNumber").invoke(listFormat);
                if (listNumber instanceof Integer && (Integer) listNumber > 0) {
                    return "- " + text;
                }
            }
        } catch (Exception e) {
            // 没有列表格式,返回 null
        }
        return null;
    }

    @Test
    public  void a() {

        try {
            // 转换.doc文件  第一个参数是word文件所在路径,第二个是希望输出的文件路径及命名
            convertDoc("C:\\***\\***.doc", "D:\\***\\output_from_doc.md");
            log.info("转换完成");
        }catch (Exception e){
            log.error("转换失败:"+e);
        }
    }

3、自此,转换已完成,若想要docx格式的转md 可参考下面

java 复制代码
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNumPr;

import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;

public class WordToMarkdown {

    // 转换 .doc 格式文件
    public void convertDoc(String inputPath, String outputPath) throws IOException {
        try (HWPFDocument document = new HWPFDocument(new FileInputStream(inputPath));
             FileWriter writer = new FileWriter(outputPath)) {

            Range range = document.getRange();
            for (int i = 0; i < range.numParagraphs(); i++) {
                Paragraph para = range.getParagraph(i);
                String text = para.text().trim();
                if (text.isEmpty()) continue;

                // 处理标题
                String mdText = processDocHeading(para, text);
                if (mdText != null) {
                    writer.write(mdText + "\n\n");
                    continue;
                }

                // 处理列表
                mdText = processDocList(para, text);
                if (mdText != null) {
                    writer.write(mdText + "\n\n");
                    continue;
                }

                // 普通段落
                writer.write(text + "\n\n");
            }
        }
    }

    // 转换 .docx 格式文件
    public void convertDocx(String inputPath, String outputPath) throws IOException {
        try (XWPFDocument document = new XWPFDocument(new FileInputStream(inputPath));
             FileWriter writer = new FileWriter(outputPath)) {

            for (XWPFParagraph para : document.getParagraphs()) {
                String text = para.getText().trim();
                if (text.isEmpty()) continue;

                // 处理标题
                String mdText = processDocxHeading(para, text);
                if (mdText != null) {
                    writer.write(mdText + "\n\n");
                    continue;
                }

                // 处理列表
                mdText = processDocxList(para, text);
                if (mdText != null) {
                    writer.write(mdText + "\n\n");
                    continue;
                }

                // 普通段落
                writer.write(text + "\n\n");
            }
        }
    }

    // 处理 .doc 标题
    private String processDocHeading(Paragraph para, String text) {
        int styleIndex = para.getStyleIndex();
        // 标题样式索引通常为 0-5 对应 1-6 级标题
        if (styleIndex >= 0 && styleIndex <= 5) {
            return repeat("#", styleIndex + 1) + " " + text;
        }
        return null;
    }

    // 处理 .doc 列表
    private String processDocList(Paragraph para, String text) {
        // 兼容处理列表判断,避免使用可能不存在的方法
        try {
            // 通过反射检查是否有 getListFormat 方法
            Object listFormat = para.getClass().getMethod("getListFormat").invoke(para);
            if (listFormat != null) {
                // 检查是否有列表编号
                Object listNumber = listFormat.getClass().getMethod("getListNumber").invoke(listFormat);
                if (listNumber instanceof Integer && (Integer) listNumber > 0) {
                    return "- " + text;
                }
            }
        } catch (Exception e) {
            // 没有列表格式,返回 null
        }
        return null;
    }

    // 处理 .docx 标题
    private String processDocxHeading(XWPFParagraph para, String text) {
        String styleName = para.getStyle();
        if (styleName != null && styleName.startsWith("Heading")) {
            try {
                int level = Integer.parseInt(styleName.replaceAll("[^0-9]", ""));
                if (level >= 1 && level <= 6) {
                    return repeat("#", level) + " " + text;
                }
            } catch (NumberFormatException e) {
                // 忽略格式错误的标题
            }
        }
        return null;
    }

    // 处理 .docx 列表
    private String processDocxList(XWPFParagraph para, String text) {
        CTP ctp = para.getCTP();
        if (ctp == null) return null;
        
        CTPPr pPr = ctp.getPPr();
        if (pPr == null) return null;
        
        CTNumPr numPr = pPr.getNumPr();
        if (numPr != null) {
            return "- " + text;
        }
        return null;
    }

    // 字符串重复方法(兼容 JDK8)
    private String repeat(String str, int times) {
        if (times <= 0) return "";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < times; i++) {
            sb.append(str);
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        WordToMarkdown converter = new WordToMarkdown();
        try {
            // 转换 .doc 文件
            converter.convertDoc("input.doc", "output_doc.md");
            
            // 转换 .docx 文件
            converter.convertDocx("input.docx", "output_docx.md");
            
            System.out.println("转换完成!");
        } catch (IOException e) {
            System.err.println("转换失败:" + e.getMessage());
            e.printStackTrace();
        }
    }
}
相关推荐
清水白石0081 小时前
深入解析 LRU 缓存:从 `@lru_cache` 到手动实现的完整指南
java·python·spring·缓存
林开落L1 小时前
从零开始学习Protobuf(C++实战版)
开发语言·c++·学习·protobuffer·结构化数据序列化机制
牛奔1 小时前
Go 是如何做抢占式调度的?
开发语言·后端·golang
符哥20081 小时前
C++ 进阶知识点整理
java·开发语言·jvm
小猪咪piggy1 小时前
【Python】(4) 列表和元组
开发语言·python
Sayuanni%32 小时前
初阶_多线程1(线程含义与关键属性)
java
程序媛徐师姐2 小时前
Java基于微信小程序的模拟考试系统,附源码+文档说明
java·微信小程序·java模拟考试系统小程序·模拟考试微信小程序·模拟考试系统小程序·模拟考试小程序·java模拟考试小程序
難釋懷2 小时前
Lua脚本解决多条命令原子性问题
开发语言·lua
CoderCodingNo2 小时前
【GESP】C++ 二级真题解析,[2025年12月]第一题环保能量球
开发语言·c++·算法
疯狂敲代码的老刘2 小时前
JDK 1.6到25 全版本网盘合集 (Windows + Mac + Linux)
java·linux·windows·macos·jdk