首頁(yè)技術(shù)文章正文

自己動(dòng)手編寫清理工具:清理MarkDown文檔中多余的圖片【Java培訓(xùn)】

更新時(shí)間:2022-08-24 來源:黑馬程序員 瀏覽量:

  作者原創(chuàng):黑馬程序員講師——?jiǎng)⒉?版權(quán)所有

  引入

  Markdown文檔的好處

  相信很多朋友在開發(fā)和工作過程中都會(huì)使用MarkDown格式來編寫文檔,Markdown文檔的好處多多:

  - 它基于純文本,方便修改和共享;

  - 幾乎可以在所有的文本編輯器中編寫;

  - 有眾多編程語言的實(shí)現(xiàn)和應(yīng)用的相關(guān)擴(kuò)展;

  - 在 GitHub 等網(wǎng)站中有很好的應(yīng)用;

  - 很容易轉(zhuǎn)換為 HTML 文檔或其他格式;

  - 適合用來編寫文檔、記錄筆記、撰寫文章。

  而在眾多的MarkDown文檔的編輯器中,我們比較常用的一款工具是Typora,前幾年是免費(fèi)的,最近1.0正式版以后開始要收費(fèi)了。

  

1661320289489_1.jpg

  Typora的優(yōu)勢(shì)

  Typora容許隨時(shí)隨地開展無縫拼接瀏覽,從而可以在編輯的同時(shí)及時(shí)的看到效果。筆者現(xiàn)在寫這個(gè)文檔就是使用的這個(gè)工具。它有以下好處:

  1. 在Win,Mac和Linux上能用

  2. 它具備審校作用,能夠檢查拼讀和英語的語法

  3. 全自動(dòng)匹配Markdown標(biāo)記,比如括弧

  4. 支持大概100種語言并支持英語的語法突顯

  5. 豐富多彩的作用和鍵盤快捷鍵

  6. 與內(nèi)聯(lián)公式和顯示信息公式適配

  Typora的不足

  工具可以做到圖文并茂的編寫文檔,所有插入的圖片默認(rèn)放在當(dāng)前文檔的assets目錄下,也可以通過設(shè)置指定圖片保存的位置,使用起來很方便。

  

1661320332512_2.jpg

  但不足的是,如果文檔進(jìn)行了修改,圖片從文檔中刪除了,殘留在當(dāng)前目錄下的assets目錄下的圖片并不會(huì)一同刪除。隨著文檔不斷的更新和修改,這個(gè)目錄下的圖片文件會(huì)越留越多,有時(shí)多達(dá)幾十M。不但占用空間,而且毫無用處。

<img src="assets/image-20220721102804143.png" alt="image-20220721102804143" style="zoom:80%;" />

  雖然我們可以手動(dòng)點(diǎn)擊每張圖片查看具體是哪張圖片,再一張張手工去刪除,但圖片如果多的話,也是很繁瑣的事情,而且考驗(yàn)人的耐心。

<img src="assets/image-20220721102924085.png" alt="image-20220721102924085" style="zoom:80%;" />

  我們能不能自己寫個(gè)程序,分析整個(gè)Markdown文檔中的圖片地址,然后批量刪除呢?有了這個(gè)想法以后,我就自己花了一些時(shí)間做了一個(gè),目前已經(jīng)使用了一年多了,沒有發(fā)現(xiàn)什么問題,特意寫出來分享給大家。

  實(shí)現(xiàn)思路

  思路

  首先我們需要分析Markdown文檔的格式,它本質(zhì)上就是一個(gè)文本文件。大致實(shí)現(xiàn)思路如下:

  1. 使用Java中的IO流API對(duì)文檔進(jìn)行解析

  2. 找到文檔中圖片的地址,使用正則表達(dá)式進(jìn)行分析,將所有文檔中出現(xiàn)的圖片文件名保存成一個(gè)集合。

  3. 再到assets文件夾下去查找所有的圖片文件名,也保存成一個(gè)集合。

  4. 對(duì)比兩個(gè)文件名的集合,將在assets目錄下存在的文件,文檔中不存在的圖片文件全部找出來

  5. 刪除所有不存在的圖片文件

  源代碼

```java
package org.newboy.utils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author NewBoy
 * @version 1.0
 * @since 2020-12-04
 * 刪除MarkDown目錄下多余的圖片文件
 */
public class MarkDownPictureCleaner {


    public static void main(String[] args) {
        System.out.println("=== MarkDown下冗余圖片清理工具(開發(fā)者:NewBoy 版本:1.0) ===");

        Scanner scanner = new Scanner(System.in);

        //MarkDown的文件名
        String path = null;
        try {
            System.out.println("請(qǐng)輸入Markdown文件的路徑和文件名(可直接將md文件拖到命令窗口):");
            path = scanner.nextLine();
        } catch (Exception e) { // 用戶可能按下 Ctrl + C 終止程序
            System.out.println("程序結(jié)束!");
            scanner.close();
            System.exit(0);
        }

        // 預(yù)檢查,判斷用戶輸入的文件是否存在
        File file = null;

        //圖片所在目錄
        String picDir = null;

        if (StringUtils.isNotBlank(path)) {
            //如果用戶在DOS命令窗口拖入,前后有雙引號(hào),去掉雙引號(hào)
            path = path.trim().replace("\"", "");
            //創(chuàng)建文件對(duì)象
            file = new File(path);
            if (!file.exists()) {
                System.out.println("Markdown文件不存在!");
                file = null;
            }
            else {
                System.out.println("請(qǐng)輸入圖片目錄(默認(rèn)為assets):");
                //圖片所在目錄
                picDir = scanner.nextLine();
                //如果為空,空串,或者空格
                if (StringUtils.isBlank(picDir)) {
                    picDir = "assets";
                }
            }
        }

        // 讀取 Markdown 文件的內(nèi)容
        String content = null;
        if (file != null) { // 如果用戶輸入的文件不存在,跳過此次操作
            System.out.println("您輸入的路徑:" + file.getAbsolutePath());
            try {
                content = FileUtils.readFileToString(file, "UTF-8");
            } catch (IOException e) {
                System.out.println("文件讀取異常:" + e.getMessage());
                content = null;
            }
        }

        if (content != null) {
            // 找出 Markdown 文件中所有圖片的引用
            String regex = "(!\\[.*\\])(\\(.*\\))|(<img\\b.*?(?:\\>|\\/>))"; // 捕獲組,匹配類似于 "![*](*)" 的字符串
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(content);
            HashSet<String> picturesInMarkdown = new HashSet<>();

            while (matcher.find()) {
                String ref = matcher.group(0);
                String picture = null;
                int beginIndex = 0;
                int endIndex = 0;
                //如果是!開頭
                if (ref.startsWith("!")) {
                    // 獲取圖片名稱
                    beginIndex = ref.lastIndexOf("/") + 1;
                    endIndex = ref.length() - 1;
                } else if (ref.startsWith("<")) { //或者以<開頭的
                    beginIndex = ref.indexOf("/") + 1;
                    endIndex = ref.indexOf('"', beginIndex);
                }
                picture = ref.substring(beginIndex, endIndex);
                //logger.info(picture);
                // 保存圖片名稱
                picturesInMarkdown.add(picture);
            }

            System.out.println("MarkDown中一共有:" + picturesInMarkdown.size() + "個(gè)圖片文件");
            // 列出 Markdown 文件所在目錄中的圖片名稱
            File directory = file.getParentFile();
            String[] extensions = {"png", "jpg", "jpeg", "bmp"}; // 圖片擴(kuò)展名
            boolean recursive = true; // 不掃描子目錄
            HashSet<String> picturesInDirectory = new HashSet<String>();
            //獲取所有文件的集合
            Collection<File> files = FileUtils.listFiles(directory, extensions, recursive);
            System.out.println("圖片目錄下一共有:" + files.size() + "個(gè)圖片文件");

            for (File picture : files) {
                String name = picture.getName();
                picturesInDirectory.add(name);
            }

            // 列出冗余圖片,并將其刪除
            picturesInDirectory.removeAll(picturesInMarkdown);
            int count = 0;
            for (String picture : picturesInDirectory) {
                String pic = directory.getAbsolutePath() + File.separator + picDir + File.separator + picture;

                System.out.println("刪除圖片:" + pic);
                FileUtils.deleteQuietly(new File(pic));
                count++;
            }
            System.out.println("操作完成,共刪除了" + count + "個(gè)圖片文件!");
        }

        scanner.close();
        System.exit(0);
    }
}
```

  
       使用說明

  因?yàn)槭褂肑ava編寫,使用需要安裝Java虛擬機(jī),為了方便用戶的使用,特意編寫了一個(gè)DOS下的命令行

```
@echo off
java -jar markdown-picture-cleaner-1.0.jar
pause
```

  1. 運(yùn)行的時(shí)候會(huì)出現(xiàn)一個(gè)窗口,需要輸入Markdown文件的路徑和文件名,這個(gè)比較麻煩,但可以將需要清理的文件直接拖到窗口中,則會(huì)自動(dòng)填充文件路徑和文件名

1661320535158_3.jpg

  2. 拖到窗口中會(huì)自動(dòng)輸入路徑和文件名

  <img src="assets/image-20220721105304355.png" alt="image-20220721105304355" style="zoom:80%;" />

  3. 按下回車會(huì)讓你輸入圖片的目錄,默認(rèn)是當(dāng)前目錄下的assets,如果圖片是在這個(gè)目錄下,直接按回車即可。

  1661320595394_4.jpg

  4. 最后顯示清理的結(jié)果

  1661320627052_5.jpg

  最后

  以上是給各位讀者提供了一種思路,大家也可以使用其它語言進(jìn)行編寫,比如可以直接運(yùn)行在Windows下的VC或是VB,還有圖形界面,用戶體驗(yàn)會(huì)更好一些。同時(shí)軟件本身只提供了基礎(chǔ)功能,作者提供了源代碼,懂Java的朋友可以在這個(gè)基礎(chǔ)上去進(jìn)一步完善。

分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!