说明:使用的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、实现代码
// 转换 .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 可参考下面
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();
}
}
}