markdown 插入图片默认是放到本地的, 如果你在markdown文件里面删除了图片,但是本地图片是还存在的,
于是我写了个小工具删除这个没有用的图片
其实就是遍历电脑上所有的markdown文件, 找出markdown里面的图片, 和我typora设置保存图片的地址里面的所有的图片去匹配,如果markdown没有typora的图片的引用, 就认为是废弃的图片,就把这个图片改个名字,后面拼接一个待删除的后缀,再剪切到别的文件夹里面,为什么不直接删除,目的就是防止程序出现bug导致的误删. 如果真不小心误删除了, 直接给图片后缀"待删除"删掉,放到markdown图片,还能接着使用.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<commons-io.version>2.6</commons-io.version>
<commons-lang3.version>3.9</commons-lang3.version>
<logback-classic.version>1.2.3</logback-classic.version>
</properties>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback-classic.version}</version>
</dependency>
</dependencies>
<build>
<!--<pluginManagement><!– lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) –>-->
<plugins>
<plugin>
<!--<groupId>org.apache.maven.plugins</groupId>-->
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin </artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.bd.util.appclient.AppMain</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<!--</pluginManagement>-->
</build>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 定义日志文件的输出路径 -->
<!-- <property name="USER_HOME" value="G:/log" /> -->
<!-- 输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<!-- 基于大小以及时间的轮转策略 -->
<!-- 参考:http://www.logback.cn/04%E7%AC%AC%E5%9B%9B%E7%AB%A0Appenders.html -->
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 要写入文件的名称。如果文件不存在,则新建。 -->
<!-- <file>${USER_HOME}/logback.log</file> -->
<file>logback.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>%d{yyyyMMdd}/logback-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100KB</maxFileSize>
<!-- 最多保留多少数量的归档文件,将会异步删除旧的文件。 -->
<maxHistory>30</maxHistory>
<!-- 所有归档文件总的大小。当达到这个大小后,旧的归档文件将会被异步的删除。 -->
<totalSizeCap>1000MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level [%-10thread] %logger - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="info">
<appender-ref ref="ROLLING" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
package com.zjj;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PictureClear {
static ArrayList<String> targetPath = new ArrayList<>();
static Logger logger = LoggerFactory.getLogger(PictureClear.class);
//这个列表是有图片的markdown.
static HashSet<String> markdownNameSet = new HashSet<>();
//所有markdown里面所有的图片
static HashSet<String> pictureNameInMarkdown = new HashSet<>();
// 图床路径
// public static String figureBedPath = "D:\\Users\\微云同步助手\\软件配置备份\\typora图片存储\\";
public static String figureBedPath ;
// 删除目录
// public static String toDeletePath = figureBedPath + "toDelete" + "\\";
public static String toDeletePath;
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
init(args);
//获取带图片的md文件列表
doSearchBandPicMD();
//微云所有的图片
HashSet<String> weiyun = getFigureBedFileList();
// 将不匹配的图片重命名并且挪到 toDelete文件夹里面
doReName(pictureNameInMarkdown, weiyun);
System.out.println("完成时间:" + (System.currentTimeMillis() - start));
}
private static void init(String[] args) {
// 赋值
PictureClear.figureBedPath = args[0]; //图床路径
PictureClear.toDeletePath = args[1]; // 删除路径
String arg = args[2];
String[] split = arg.split(",");
for (String s : split) {
targetPath.add(s + ":\\");
}
// targetPath.add("E:\\");
// targetPath.add("D:\\");
if (!new File(toDeletePath).exists()) {
new File(toDeletePath).mkdirs();
}
}
private static void doSearchBandPicMD() throws IOException {
for (String path : targetPath) {
File[] files = new File(path).listFiles();
for (File file : files) {
if (file.isHidden()) {
// 隐藏文件直接跳过
continue;
}
logger.info("开始检索目录 :" + file.getPath());
if (file.isFile()) {
String name = file.getName();
String[] split = name.split("\\.");
String fileNameNow = split[split.length - 1];
if ("md".equals(fileNameNow)) {
doSetMarkdownNameList(file, name);
}
} else {
doRecursionSearchMDFile(file);
}
}
}
}
/**
* 递归
* 张俊杰 2021年01月29日 10:08
*/
private static void doRecursionSearchMDFile(File file2) throws IOException {
File[] files = file2.listFiles();
for (File file : files) {
if (file.isHidden()) {
// 隐藏文件直接跳过
continue;
}
logger.info("开始检索目录 :" + file.getPath());
if (file.isFile()) {
String name = file.getName();
String[] split = name.split("\\.");
String fileNameNow = split[split.length - 1];
if ("md".equals(fileNameNow)) {
doSetMarkdownNameList(file, name);
}
} else {
doRecursionSearchMDFile(file);
}
}
}
private static void doSetMarkdownNameList(File file, String name) throws IOException {
String s1 = FileUtils.readFileToString(file, "UTF-8");
String regex = "(!\\[.*\\])(\\(.*\\))"; // 捕获组,匹配类似于 "" 的字符串
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(s1);
while (matcher.find()) {
String ref = matcher.group(0);
// 获取图片名称
int beginIndex = ref.indexOf("](") + 2;
int endIndex = ref.length() - 1;
String pictureName = ref.substring(beginIndex, endIndex);
// 保存图片名称
if (pictureNameInMarkdown.add(pictureName)) {
markdownNameSet.add(file.getPath());
}
}
}
/**
* 获取图床文件列表, 排除掉 范围之外的.
* 张俊杰 2021年01月28日 18:59
*/
private static HashSet<String> getFigureBedFileList() {
File file = new File(figureBedPath);
HashSet<String> result = new HashSet<>();
File[] files = file.listFiles();
for (File file1 : files) {
if (file1.isDirectory()) {
String Path = file + "\\" + file1.getName();
if (new File(Path).compareTo(new File(toDeletePath)) == 0) {
continue;
}
// System.out.println("Path = " + Path);
// System.out.println("toDeletePath = " + toDeletePath);
// if (Path.equals(toDeletePath)) {
//
// }
File file2 = new File(Path);
File[] files1 = file2.listFiles();
for (File file3 : files1) {
result.add(Path + "\\" + file3.getName());
}
}
}
return result;
}
private static void doReName(HashSet<String> picturesInMarkdown, HashSet<String> weiyun) {
// HashSet<String> toDelDir = new HashSet<>();
for (String wy : weiyun) {
boolean flag = baohan(wy, picturesInMarkdown);
if (!flag) {
reName(wy);
}
}
}
/**
* 判断是否在hashset里面包含
* 张俊杰 2021年01月28日 18:59
*/
private static boolean baohan(String wy, HashSet<String> picturesInMarkdown) {
boolean equals = false;
for (String s : picturesInMarkdown) {
equals = s.equals(wy);
if (equals) {
break;
}
}
return equals;
}
/**
* 将文件移动到 指定名录,同时名字后面追加待删除 名字
* 张俊杰 2021年01月28日 18:22
*/
private static void reName(String wy) {
//获取需要剪切的文件
File file = new File(wy);
String[] split = file.getPath().split("\\\\");
String s = split[split.length - 2]; // 子目录的名字
File targetFile = new File(figureBedPath + s);
//
logger.info("将要重命名文件 : " + file);
boolean flag = file.renameTo(new File(toDeletePath + "\\" + file.getName() + "待删除"));
if (flag) {
// 如果是空的文件夹就直接删除掉
if (targetFile.length() == 0) {
logger.info("删除了这个空文件夹: " + targetFile);
targetFile.delete();
}
}
}
}
直接Maven package命令打包,这个就不说了.
你会发现有个 demo-1.0-SNAPSHOT-jar-with-dependencies.jar 文件
set figureBedPath=D:\\Users\\微云同步助手\\软件配置备份\\typora图片存储\\
set toDeletePath=D:\\Users\\微云同步助手\\软件配置备份\\typora图片存储\\toDelete\\
set ScanningDrive=D,E
java -classpath demo-1.0-SNAPSHOT-jar-with-dependencies.jar com.zjj.PictureClear [%figureBedPath% %toDeletePath% %ScanningDrive% ]
说明, figureBedPath是 你markdown图片存储的路径,和上面typora是有对应关系的, 看上面的配置D:\Users\微云同步助手\软件配置备份\typora图片存储\${filename} , 你把 ${filename} 删掉就行了.
toDeletePath是不存在的文件要移动到哪里去,
ScanningDrive 把你要放markdown的磁盘都写上,假如说我C盘和D盘放markdown,那么就给c和d都写上… 建议给你所有盘符都写上.,
D:\Users\微云同步助手\软件配置备份\typora图片存储${filename}
我上传的图片会到这个文件夹下面,
如果我markdown删除了图片, 我程序会扫描到发现markdown没这个图片,
就会给这个图片挪到toDelete文件夹下,
目的就是防止误删除, 所以放到这里,你只需要给 “待删除” 这个结尾删除就行了,图片就又能显示了.
一、python语言分类1. C pythonc语言的python版本 官方推荐使用C语言实现,使用最为广泛,CPython实现会将源文件(py文件)转换成字节码文件(pyc文件),然后运行在Python虚拟机上。2. Jython java pythonPython语言的Java实现,不仅提供Python的库,同时也提供所有的Java类。能运行在任何可兼容的Java1.1或更高的Java虚拟...
wso2 每个集成架构师或开发人员都应该熟悉Gregor Hohpe和Bobby Woolf所描述的企业集成模式(EIP) 。 模式之一是“内容消息过滤器” (不要与消息过滤器模式混淆)。使用不同的Mediator在WSO2中有多种方法可以实现此目的。 一种方法是使用XSLT介体,您可以在其中简单地使用XSLT进行过滤。 另一个(根据其名称不太明显)是Enrich Mediator 。 这...
前面我们详细分析了从应用层调用CameraManager的openCamera的方法来打开相机的逻辑,上次的分析我们来到了CameraServer进程当中,但是还没有真正看到open操作设备节点来实现真正打开的逻辑,遗留的问题也就是从frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp文件中的st...
作者:micheal7500转自:http://blog.chinaunix.net/uid-20539088-id-115747.html前言: 尽管linux-2.6.31直接提供了对mini2440的支持,但移植过程中发现存在的问题比较多,所以最后决定使用linux-2.6.30.4来完成这次移植过程!0)、准备工作交叉编译器使用codesour
LightGBM与XGBOOST算法概述LightGBM: 用于排序,分类,回归等机器学习任务,支持高效率并行训练XGBOOST:来源于GBDTLightGBM与XGBOOST相关理论基础:Boosting集成学习的一个分支,通过将弱分类器训练成强分类器,达到准确分类的效果Gradient boostingBoosting分为Adaboost和Gradient Boosting,lightGBM属于gradient boosting? 什么是gradient boosting,与adabo
javascript事件列表解说事件 浏览器支持 解说一般事件 onclick IE3、N2 鼠标点击时触发此事件ondblclick IE4、N4 鼠标双击时触发此事件onmousedown IE4、N4 按下鼠标时触发此事件onmouseup IE4、N4 鼠标按下后松开鼠标时触发此事件onmouseover IE3、N2 当鼠标移动到某对象范围的上方时触发此事件onmousemove IE4、N4 鼠标移动时触发此事件onmouseout IE4、N3 当鼠标离开某对象范围时触发此事件
unity里面打开网页接触了一些,没做深入研究,仅以简单展示网页为主。分为两类,一是PC端打开网页,二是android端打开网页。网页插件或方案Unity之PC版,window。如果网页只是单独二维码图片,则采用www请求得到www.texture;Unity之PC版,window。如果网页不是单独一张二维码图片,有其他文字,样式,js等,使用插件WWebView(该插件开通了...
1. 项目核心代码结构截图 jeesz-utils jeesz-config jeesz-framework jeesz-core-cms jeesz-core-gen jeesz-core-bookmark
题目描述计算字符串最后一个单词的长度,单词以空格隔开。输入描述一行字符串,非空,长度小于5000。输出描述整数N,最后一个单词的长度。示例输入:hello world输出:5思路利用 getline() 函数读取整行字符串,从字符串末尾开始,向前计数,遇到空格停止。#include <iostream>#include <string>usin...
CRT显示器简介 CRT显示器学名为“阴极射线显像管”,是一种使用阴极射线管(Cathode Ray Tube)的显示器。主要有五部分组成:电子枪(Electron Gun)、偏转线圈(Deflection coils)、荫罩(Shadow mask)、高压石墨电极和荧光粉涂层(Phosphor)及玻璃外壳。它是应用最广泛的显示器之一,CRT纯平显示器具有可视角度大、无坏点、色彩还原度高、色度均
委托绝对算是C#中一个非常重要和新颖的概念。可以直观的理解成一个安全的函数指针。delegate实际是如何工作的呢?delegate int MyDelegate(int x, int y);//生成自动化的类代码如下sealed class MyDelegate : System.MulticastDelegate{ public int Invoke(int x,i...
为什么80%的码农都做不了架构师?>>> ...