Java实现markdown(md)文档网络图片下载,替换链接为本地

        将别人的博客、文章和语雀笔记转换为markdown文档后,上面的图片资源都是存储在网络上,这即不方便离线查看,也不安全(比如该图片网络资源失效)。于是我就想找一个工具可以将整个文档的图片资源都下载到本地,并将图片的网络链接换成本地路径。

        在网上找了一下后,发现基本都是使用python语言或js实现的,没有用java实现的,于是就打算自己写一个java实现的。为了通用性,我也把它转成了exe文件(使用工具:exe4j),但仍然需要java环境,需要有环境变量JAVA_HOME;如果想让它在没有java环境下的电脑使用,可以将jdk(jre)与exe文件一起打包供别人使用(需在将jar包转换为exe时将jdk指定为相当路径,具体方法参照:exe4j打包jar成exe在无jdk环境上运行 - 简书 (jianshu.com))。但对这样一个几百kb的小工具,这样做就太傻了,所以仅供有兴趣者自己尝试。

        jar文件地址:【免费】用java实现的将markdown(md)文档的网络图片下载到本地,并替换原图片地址为本地路径_java获取markdown内容里面的图片资源-CSDN文库

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MarkdownImageDownloader {
	public static final String Local_PATH_REG = "!\\[.*?]\\(([A-Z]:.*?)\\)";
	public static final String IMG_URL_REG = "!\\[.*?]\\((http.*?)\\)"; // 匹配图片链接地正则表达式
	public static final String IMG_TYPE_REG = "\\.(jpg|jpeg|png|gif|bmp|webp)";    // 匹配图片格式的正则表达式
	public static final String ILLEGAL_CHAR_REG = "[/:*?\\\\<>\"]";  // 匹配文件名非法字符的正则表达式

	public static void main(String[] args) {
		// 打开文件下载窗口选择文件,从而获得markdown文件的路径
		FileDialog dialog = new FileDialog(new JFrame());
		dialog.setVisible(true);
		String filePath = null; // 选择的markdown文件的路径
		if (dialog.getDirectory() == null || dialog.getFile() == null) {
			System.exit(1);
		} else {
			filePath = dialog.getDirectory() + dialog.getFile();
		}

		// 构建md保存根路径和图片保存路径
		int index = filePath.lastIndexOf(File.separator);
		String mdPath = filePath.substring(0, index + 1);
		String imgDirectoryName = filePath.substring(index + 1, filePath.length() - 3) + "img";
		String imgDirectoryPath = mdPath + imgDirectoryName;

		try {
			// 获取md文件内容
			String mdContent = getMdContent(filePath);
			// 创建存放图片的文件夹
			Files.createDirectories(Paths.get(imgDirectoryPath));

			// 如果图片是本地的,这将图片复制到新的图片目录下
			mdContent = copyLocalImg(imgDirectoryName, imgDirectoryPath, mdContent);

			// 获得图片网络地址,并从网络上下载图片到本地;最后把markdown文档的图片标签换成本地路径
			mdContent = downloadImg(imgDirectoryName, imgDirectoryPath, mdContent);

			// 构建副本
			String mdName = imgDirectoryName.substring(0, imgDirectoryName.length() - 3) + "_new.md";
			try (FileWriter writer = new FileWriter(mdPath +mdName, StandardCharsets.UTF_8)) {
                writer.write(mdContent);
                writer.flush();
            }

			JOptionPane.showMessageDialog(null, "任务完成!");
			System.exit(0);
		} catch (IOException e) {
			JOptionPane.showMessageDialog(null, "任务失败!", "IO异常", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
		}
		System.exit(1);
	}

	private static String copyLocalImg(String imgDirectoryName, String destPath, String mdContent) throws IOException {
		Pattern compile = Pattern.compile(Local_PATH_REG);
		Matcher matcher = compile.matcher(mdContent);
		while (matcher.find()){
			String imgPath = matcher.group(1);
			// 获取图片的文件名
			int start = imgPath.lastIndexOf(File.separator) + 1;
			int index = imgPath.indexOf("?");
			int end = index == -1 ? imgPath.length() : index;
			String imgName = imgPath.substring(start, end);
			Files.copy(Paths.get(imgPath.substring(0, end)), Paths.get(destPath + File.separator + imgName),
					StandardCopyOption.REPLACE_EXISTING);
			mdContent = mdContent.replace(imgPath, imgDirectoryName + "/" + imgName);
		}
		return mdContent;
	}

	private static String getMdContent(String filePath) throws IOException {
		// 将markdown文件读入内存,保存到字符串变量stringBuilder中
		StringBuilder stringBuilder = new StringBuilder();
		try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8))) {
			String line;
			while ((line = br.readLine()) != null)
				stringBuilder.append(line).append("\n");
		}
        return stringBuilder.toString();
	}

	private static String downloadImg(String imgDirectoryName, String destPath, String mdContent) throws IOException {
		Pattern pattern = Pattern.compile(IMG_URL_REG); // 匹配url
		Matcher matcher = pattern.matcher(mdContent);    // 构建匹配器
		Pattern imgTypePattern = Pattern.compile(IMG_TYPE_REG);  // 匹配图片格式
		while (matcher.find()) {
			String imgUrl = matcher.group(1);   // 匹配匹配器第一个括号里的内容
			Matcher imgTypeMatcher = imgTypePattern.matcher(imgUrl);
			// 开始获取图片的文件名
			String imgName;
			if (imgTypeMatcher.find()) {
				String imgType = imgTypeMatcher.group(1);
				int start = imgUrl.lastIndexOf("/") + 1;
				int end = imgUrl.lastIndexOf(imgType) + imgType.length();
				imgName = imgUrl.substring(start, end).replaceAll(ILLEGAL_CHAR_REG, "");
			} else {
				imgName = imgUrl.substring(imgUrl.lastIndexOf("/") + 1).replaceAll(ILLEGAL_CHAR_REG, "");
			}
			try (InputStream inputStream = new URL(imgUrl).openStream()) {
				try (ReadableByteChannel rbc = Channels.newChannel(inputStream)) {
					try (FileOutputStream fos = new FileOutputStream(destPath + File.separator + imgName)) {
						fos.getChannel().transferFrom(rbc, 0L, Long.MAX_VALUE);     // 写入图片文件
					}
				}
			}
			mdContent = mdContent.replace(imgUrl, imgDirectoryName + "/" + imgName);
		}
		return mdContent;
	}
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值