typora 瘦身
1、参考资料
- https://blog.csdn.net/zha_ojunchen/article/details/107029846
2、Why?
- 当使用如下设置时,复制黏贴的图片会自动保存在这个 {filename}.assets 文件夹中
- 问题来了,复制文件,图片会自动保存到 assets 文件夹,并在 Markdown 文件产生该图片链接语法:
![]()
- 但是删除、修改 Markdown 中的图片链接语句,并不会删除 assets 文件夹中的图片,这导致了经常assets 文件夹会产生很大的无用图片,感觉这是是 Markdown 存储的一个痛点

3、目标
- 编写 Java 代码,对 Typora 进行瘦身,删除本地无用的图片
4、代码
- 大致思路:使用递归遍历整个笔记根目录
- 如果遇到 MD 文件,则使用正则表达式匹配文中所用到的图片标签:
![]()
,进而获取文中所引用的图片名称 - 我们将文中所引用的图片名称和本地图片名称做差集,便能得到无用的图片,删除即可
public class TyporaClean {
public static void main(String[] args) {
String noteRootPath;
if (args == null || args.length == 0) {
noteRootPath = "D:\\我的坚果云";
} else {
noteRootPath = args[0];
}
doClean(noteRootPath);
}
private static void doClean(String destPath) {
File destPathFile = new File(destPath);
File[] allFiles = destPathFile.listFiles();
for (File curFile : allFiles) {
Boolean isDirectory = curFile.isDirectory();
if (isDirectory) {
String absolutePath = curFile.getAbsolutePath();
if (absolutePath.endsWith(".assets")) {
continue;
}
doClean(absolutePath);
} else {
doSinglePicClean(curFile);
}
}
}
public static void doSinglePicClean(File curFile) {
String curFileName = curFile.getName();
Boolean isMd = curFileName.endsWith(".md");
if (!isMd) {
return;
}
String curFilNameWithoutMd = curFileName.replace(".md", "");
String curAssetName = curFilNameWithoutMd + ".assets";
String curAssetAbsolutePath = curFile.getParent() + "\\" + curAssetName;
File curAssetFile = new File(curAssetAbsolutePath);
Boolean iscurAssetExist = curAssetFile.exists();
if (iscurAssetExist) {
CleanUnnecessaryPic(curFile, curAssetFile);
}
}
public static void CleanUnnecessaryPic(File curFile, File curAssetFile) {
File[] allPicFiles = curAssetFile.listFiles();
String[] usedPicNames = getUsedPicNames(curFile);
CleanUnusedPic(allPicFiles, usedPicNames);
}
public static String[] getUsedPicNames(File curFile) {
String mdFileContent = readMdFileContent(curFile);
String regex = "!\\[.*\\]\\(.+\\)";
Matcher matcher = Pattern.compile(regex).matcher(mdFileContent);
List<String> imageNames = new ArrayList<>();
while (matcher.find()) {
String curImageLabel = matcher.group();
Integer picNameStartIndex = curImageLabel.lastIndexOf("/") + 1;
Integer picNameEndIndex = curImageLabel.length() - 1;
String curImageName = curImageLabel.substring(picNameStartIndex, picNameEndIndex);
imageNames.add(curImageName);
}
String[] retStrs = new String[imageNames.size()];
return imageNames.toArray(retStrs);
}
public static String readMdFileContent(File curFile) {
StringBuilder sb = new StringBuilder();
String curLine;
try (
FileReader fr = new FileReader(curFile);
BufferedReader br = new BufferedReader(fr);
) {
while ((curLine = br.readLine()) != null) {
sb.append(curLine + "\r\n");
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
private static void CleanUnusedPic(File[] allPicFiles, String[] usedPicNames) {
if (allPicFiles == null || allPicFiles.length == 0) {
return;
}
String assetPath = allPicFiles[0].getParent();
List<String> usedPicNameList = Arrays.asList(usedPicNames);
for (File curPicFile : allPicFiles) {
String curFileName = curPicFile.getName();
boolean isUsed = usedPicNameList.contains(curFileName);
if (!isUsed) {
String curPicAbsolutePath = curPicFile.getAbsolutePath();
System.out.println("已删除无用图片:" + curPicAbsolutePath);
curPicFile.delete();
}
}
}
}
5、效果

6、警告
- 谨慎使用,图片一旦删除无法找回,回收站都没得。。。