生成Markdown目录 字符串解析 MD
Markdown版本笔记 | 我的GitHub首页 | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
文件 File 递归复制 修改后缀名 生成Markdown目录 字符串解析 MD
目录
使用方式
设计
一些常量
文件目录递归修改
递归修改文件后缀名并修改文件内容
递归修改文件后缀名
递归获取格式化后的文件名
文件复制
递归复制目录下的所有文件
复制一个文件或一个目录
复制一个文件并修改文件内容
其他工具方法
将字符串复制到剪切板
生成格式化的 Markdown 目录
生成 Markdown 的目录
用到的常量
递归为文件生成Markdown目录
插入的目录格式
其他一些用到的工具方法
源码
MDUtils
TOCUtils
DirUtils
使用方式
工具类的作用:生成GitHub
上仓库MyAndroidBlogs的REANME.MD
中博客的目录。
使用步骤式:
1、通过为知笔记导出指定目录下的所有文件,导出为U8格式的纯文本
2、执行以下代码
String DIR = "D:/为知笔记导出/导出的笔记";
MDUtils.modifyFile(new File(DIR)); //递归修改文件后缀名,同时删除不匹配的文件,并修改文件中不正常的字符
TOCUtils.insertToc(new File(DIR), false); //递归为 markdown 文件生成目录
DirUtils.getFormatFilesNames(new File(DIR)); //递归获取文件名,并将格式化后的内容复制到粘贴板
3、将粘贴板中的内容粘贴到REANME.MD
中
设计
一些常量
private static final String DIR = "D:/为知笔记导出/MyAndroidBlogs";
private static final String WEBSITE = "https://github.com/baiqiantao/MyAndroidBlogs/blob/master/";
private static final String FILTER = "MD";
private static final String SUFFIX_MD_TXT = ".md.txt";
private static final String SUFFIX_TXT = ".txt";
private static final String SUFFIX_MD = ".md";
private static final String SPACE = " ";
private static final String SPACE_FORMAT = "%20";
private static final String[] EXCLUDE_FILES = new String[]{".git", "README.md"};
private static final String[] REPLACE_STRINGS = new String[] { " " };//特殊字符
private static final String BLANK = " ";//空格
文件目录递归修改
递归修改文件后缀名并修改文件内容
/**
* 递归修改文件后缀名并修改文件内容
*/
public static void modifyFile(File from) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
}
if (from.isFile()) {
if (from.getName().contains(FILTER)) {//只处理带指定标识的文件
copyAndModifyFileContent(from, new File(from.getParent(), getNewName(from)));
}
from.delete();//删除源文件
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
from.delete();//删除空文件夹
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
modifyFile(file);//递归
} else if (file.isFile()) {
if (file.getName().contains(FILTER)) {//只处理带指定标识的文件
copyAndModifyFileContent(file, new File(file.getParent(), getNewName(file)));
}
file.delete();
}
}
listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "的文件全部不符合要求");
from.delete();//删除空文件夹
}
}
递归修改文件后缀名
/**
* 递归修改文件后缀名
*/
public static void modifyFileSuffix(File from) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
}
if (from.isFile()) {
if (from.getName().contains(FILTER)) {//只处理带指定标识的文件
from.renameTo(new File(from.getParent(), getNewName(from)));
} else {
from.delete();//删除源文件
}
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
from.delete();//删除空文件夹
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
modifyFileSuffix(file);//递归
} else if (file.isFile()) {
if (file.getName().contains(FILTER)) {//只处理带指定标识的文件
file.renameTo(new File(file.getParent(), getNewName(file)));
} else {
file.delete();
}
}
}
listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "的文件全部不符合要求");
from.delete();//删除空文件夹
}
}
/**
* 获取重命名的文件名
*/
private static String getNewName(File file) {
String name = file.getName();
if (name.endsWith(SUFFIX_MD_TXT)) { //处理指定后缀的文件
name = name.substring(0, name.indexOf(SUFFIX_MD_TXT) + SUFFIX_MD.length());
} else if (name.endsWith(SUFFIX_TXT)) {
name = name.substring(0, name.indexOf(SUFFIX_TXT)) + SUFFIX_MD;
}
return name;
}
递归获取格式化后的文件名
/**
* 获取指定目录及其子目录下的文件的文件名,并对文件名进行格式化,并存储到一个指定的集合中,并将内容复制到粘贴板
*/
public static List<String> getFormatFilesNames(File from) {
List<String> filePathList = new ArrayList<>();
getDirFormatFilesNames(filePathList, from, 0);
StringBuilder sBuilder = new StringBuilder();
for (String string : filePathList) {
System.out.print(string);
sBuilder.append(string);
}
setSysClipboardText(sBuilder.toString());
return filePathList;
}
/**
* 递归获取指定目录及其子目录下的文件的文件名,并对文件名进行格式化,并存储到一个指定的集合中
*
* @param filePathList 将结果保存到指定的集合中
* @param from 要遍历的目录
* @param curLeval 记录当前递归所在层级
*/
private static void getDirFormatFilesNames(List<String> filePathList, File from, int curLeval) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
} else if (isExcludeFile(from.getName())) {
System.out.println("----------------------" + "忽略文件" + from.getName());
return;
} else {
filePathList = filePathList == null ? new ArrayList<String>() : filePathList;
filePathList.add(getTitle(curLeval, from));
}
curLeval++;
File[] files = from.listFiles();
if (files == null || files.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
return;
}
for (File file : files) {
if (file.isDirectory()) {
getDirFormatFilesNames(filePathList, file, curLeval);//递归
} else if (file.isFile() && !isExcludeFile(file.getName())) {
filePathList.add(getTitle(curLeval, file));
}
}
}
/**
* 判断是否是忽略的文件
*/
private static boolean isExcludeFile(String fileName) {
for (String name : EXCLUDE_FILES) {
if (name.equals(fileName)) {
return true;
}
}
return false;
}
文件复制
递归复制目录下的所有文件
/**
* 递归复制目录下的所有文件
*/
public static void copyFiles(File from, File to) {
if (from == null || !from.exists() || to == null) {
throw new RuntimeException("源文件或目标文件不存在");
}
if (from.equals(to)) {
System.out.println("----------------------源文件和目标文件是同一个" + from.getAbsolutePath());
}
if (from.isDirectory()) {
if (to.isFile()) {
throw new RuntimeException("目录不能复制为文件");
}
if (!to.exists()) {
to.mkdirs();//创建目录
}
} else {
if (to.isDirectory()) {
throw new RuntimeException("文件不能复制为目录");
}
copyFile(from, to);//文件的话直接复制
return;
}
File[] files = from.listFiles();
if (files == null || files.length == 0) {
System.out.println(from.getName() + "中不存在任何文件");
return;
}
for (File file : files) {
if (file.isDirectory()) {
File copyDir = new File(to, file.getName());
if (!copyDir.exists()) {
copyDir.mkdirs();
System.out.println("创建子目录\t\t" + copyDir.getAbsolutePath());
}
copyFiles(file, copyDir);//递归
} else if (file.getName().contains(FILTER)) {
copyFile(file, new File(to, file.getName()));
}
}
}
复制一个文件或一个目录
/**
* 复制一个文件或一个目录(不会递归复制目录下的文件)
*/
public static void copyFile(File from, File to) {
if (from == null || !from.exists() || to == null) {
throw new RuntimeException("源文件或目标文件不存在");
}
if (from.equals(to)) {
System.out.println("----------------------源文件和目标文件是同一个" + from.getAbsolutePath());
}
if (from.isDirectory()) {
if (to.isFile()) {
throw new RuntimeException("目录不能复制为文件");
}
if (!to.exists()) {
to.mkdirs();//创建目录
}
return; //没有下面的刘操作
} else {
if (to.isDirectory()) {
throw new RuntimeException("文件不能复制为目录");
}
if (!to.getParentFile().exists()) {
to.getParentFile().mkdirs(); //复制父目录
}
}
try {
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream(from));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream(to));
int ch;
while ((ch = bufis.read()) != -1) {
bufos.write(ch);
}
bufis.close();
bufos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
复制一个文件并修改文件内容
/**
* 复制一个文件或目录(不会复制目录下的文件),复制的时候会修改文件中的一些内容
*/
public static void copyAndModifyFileContent(File from, File to) {
if (from == null || !from.exists() || to == null) {
throw new RuntimeException("源文件或目标文件不存在");
}
if (from.equals(to)) {
System.out.println("----------------------源文件和目标文件是同一个" + from.getAbsolutePath());
}
if (from.isDirectory()) {
if (to.isFile()) {
throw new RuntimeException("目录不能复制为文件");
}
if (!to.exists()) {
to.mkdirs();//创建目录
}
return; //没有下面的刘操作
} else {
if (to.isDirectory()) {
throw new RuntimeException("文件不能复制为目录");
}
if (!to.getParentFile().exists()) {
to.getParentFile().mkdirs(); //复制父目录
}
}
try {
BufferedReader bufr = new BufferedReader(new FileReader(from));
BufferedWriter bufw = new BufferedWriter(new FileWriter(to));
String line;
//另外开辟一个缓冲区,存储读取的一行数据,返回包含该行内容的字符串,不包含换行符,如果已到达流末尾,则返回【 null】
while ((line = bufr.readLine()) != null) {
for (String string : REPLACE_STRINGS) {
line = line.replace(string, BLANK);//替换为空格
}
bufw.write(line);
bufw.write(BLANK + BLANK);//加两个空格
bufw.newLine();// 写入一个行分隔符
bufw.flush();
}
bufr.close();
bufw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
其他工具方法
将字符串复制到剪切板
/**
* 将字符串复制到剪切板
*/
public static void setSysClipboardText(String writeMe) {
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable tText = new StringSelection(writeMe);
clip.setContents(tText, null);
}
生成格式化的 Markdown 目录
/***
* 格式化目录
*/
private static String getTitle(int level, File file) {
StringBuilder sb = new StringBuilder();
StringBuilder parentPath = new StringBuilder();
File parent = file;
for (int x = 1; x < level; x++) {
sb.append("\t");
parent = parent.getParentFile();//逐级获取父文件
parentPath.insert(0, parent.getName() + "/");//在前面插入父文件的文件名
}
sb.append("-").append(" ")//无序列表
.append("[")//超链接显示的字符
.append(file.getName().endsWith(SUFFIX_MD) ? file.getName().substring(0, file.getName().lastIndexOf(SUFFIX_MD)) : file.getName())//
.append("]")//
.append("(")//拼接超链接
.append(WEBSITE)//前缀
.append(parentPath.toString())//父目录
.append(file.getName().replaceAll(SPACE, SPACE_FORMAT))//文件名
.append(")")//
.append("\n");
return sb.toString();
}
生成 Markdown 的目录
用到的常量
private static final String HEADER_STRING = "#";
private static final char HEADER_CHAR = '#';
private static final String TOC_TITLE = "";//在目录前插入的内容
private static final String REPLACE_TOC = "[TOC]"; //目录要替换的内容
private static final String HEADER_1 = "="; //一级目录
private static final String HEADER_2 = "--"; //二级目录
private static final String PATTERN = "%s- [%s](#%s)";//标题的格式
private static final String SPACES = " ";
private static final String CODES = "%([abcdef]|\\d){2,2}";
private static final String SPECIAL_CHARS = "[\\/?!:\\[\\]`.,()*\"';{}+=<>~\\$|#]";
private static final String DASH = "-";
private static final String EMPTY = "";
private static final String AFFIX = "\t";
递归为文件生成Markdown目录
/**
* 递归为文件生成Markdown目录
*/
public static void insertToc(File from) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
}
if (from.isFile()) {
insertTocIntoFile(from, from, REPLACE_TOC, Integer.MAX_VALUE);
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
insertToc(file);//递归
} else if (file.isFile()) {
insertTocIntoFile(file, file, REPLACE_TOC, Integer.MAX_VALUE);
}
}
}
/**
* 为文件生成Markdown目录
*/
public static void insertTocIntoFile(File from, File to, String replaceAt, int deepLevel) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(from)));
String line;//当前行的内容
String previousLine = null;
List<String> contentList = new ArrayList<>();//每一行的内容集合
List<String> titleList = new ArrayList<>();//标题集合
int currentLine = 0;
int patternLineNumber = 1; //目录插在那一行
while ((line = reader.readLine()) != null) {
++currentLine;
boolean skipLine = false;
String trimLineString = line.trim();
if (trimLineString.startsWith(HEADER_STRING)) { //检测到标题
int count = getCharCount(trimLineString, HEADER_CHAR);
if (count < 1 || count > deepLevel) { //层级控制
System.out.println("----------------------------超过最大层级 " + deepLevel);
previousLine = line;
continue;
}
String headerName = trimLineString.substring(count).trim(); //去掉层级后的文字
titleList.add(getTitle(count, headerName));
} else if (line.startsWith(HEADER_1) && isNotEmpty(previousLine) && line.replaceAll(HEADER_1, "").isEmpty()) {
titleList.add(getTitle(1, previousLine));
} else if (line.startsWith(HEADER_2) && isNotEmpty(previousLine) && line.replaceAll(HEADER_2, "").isEmpty()) {
titleList.add(getTitle(2, previousLine));
} else if (patternLineNumber <= 1 && line.trim().equals(replaceAt)) {
patternLineNumber = currentLine; //找到这个字符串时就插在这一行(替换这个字符串),找到之后就不再继续找了
skipLine = true;//忽略这一行
}
if (!skipLine) {
contentList.add(line);
}
previousLine = line;
}
closeStream(reader); //必须先关掉这个读取,流才能开启写入流
if (patternLineNumber <= 0) {
System.out.println("----------------------------目录插入位置有误");
return;
}
contentList.add(patternLineNumber - 1, TOC_TITLE);//在指定位置插入目录前面的标题
for (String title : titleList) {
contentList.add(patternLineNumber, title);
patternLineNumber++;
}
writeFile(to, contentList);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeStream(reader);
}
}
/**
* 写内容到指定文件
*/
private static void writeFile(File to, List<String> contentList) {
PrintWriter writer = null;
try {
writer = new PrintWriter(new FileWriter(to));
for (String string : contentList) {
writer.append(string).append("\n");
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeStream(writer);
}
}
插入的目录格式
/**
* 插入的目录的模型
*/
private static String getTitle(int deepLevel, String headerName) {
StringBuilder title = new StringBuilder();
if (deepLevel > 1) {
for (int i = 0; i < deepLevel - 1; i++) {
title.append(AFFIX);
}
}
String headerLink = headerName.trim()//
.replaceAll(SPACES, DASH)//替换特殊字符,比如必须将空格换成'-'
.replaceAll(CODES, EMPTY)//
.replaceAll(SPECIAL_CHARS, EMPTY).toLowerCase();
title.append(DASH).append(SPACES)//格式为【%s- [%s](#%s)】或【缩进- [标题][#链接]】
.append("[").append(headerName).append("]")//
.append("(").append("#")//
.append(headerLink)//
.append(")");
return title.toString();
}
其他一些用到的工具方法
/**
* 关闭流
*/
public static void closeStream(Closeable... closeable) {
for (Closeable c : closeable) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 计算字符串中字符的个数
*/
private static int getCharCount(String string, char c) {
int count = 0;
for (int i = 0; i < string.length(); i++) {
if (string.charAt(i) == c) {
++count;
} else {
break;
}
}
return count;
}
/**
* 获取文件行数
*/
public static int getFileLines(File file) {
LineNumberReader reader = null;
try {
reader = new LineNumberReader(new FileReader(file));
reader.skip(Long.MAX_VALUE);
return reader.getLineNumber() + 1;
} catch (IOException ignored) {
} finally {
closeStream(reader);
}
return -1;
}
/**
* 判断字符串非空
*/
public static boolean isNotEmpty(String string) {
return string != null && !string.isEmpty();
}
源码
MDUtils
public class MDUtils {
private static final String FILTER = "MD";
private static final String SUFFIX_MD_TXT = ".md.txt";
private static final String SUFFIX_TXT = ".txt";
private static final String SUFFIX_MD = ".md";
private static final String[] REPLACE_STRINGS = new String[] { " " };//特殊字符
private static final String BLANK = " ";//空格
/**
* 递归修改文件后缀名并修改文件内容
*/
public static void modifyFile(File from) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
}
if (from.isFile()) {
if (from.getName().contains(FILTER)) {//只处理带指定标识的文件
copyAndModifyFileContent(from, new File(from.getParent(), getNewName(from)));
}
from.delete();//删除源文件
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
from.delete();//删除空文件夹
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
modifyFile(file);//递归
} else if (file.isFile()) {
if (file.getName().contains(FILTER)) {//只处理带指定标识的文件
copyAndModifyFileContent(file, new File(file.getParent(), getNewName(file)));
}
file.delete();
}
}
listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "的文件全部不符合要求");
from.delete();//删除空文件夹
}
}
/**
* 复制一个文件或目录(不会复制目录下的文件),复制的时候会修改文件中的一些内容
*/
private static void copyAndModifyFileContent(File from, File to) {
if (from == null || !from.exists() || to == null) {
throw new RuntimeException("源文件或目标文件不存在");
}
if (from.equals(to)) {
System.out.println("----------------------源文件和目标文件是同一个" + from.getAbsolutePath());
}
if (from.isDirectory()) {
if (to.isFile()) {
throw new RuntimeException("目录不能复制为文件");
}
if (!to.exists()) {
to.mkdirs();//创建目录
}
return; //没有下面的刘操作
} else {
if (to.isDirectory()) {
throw new RuntimeException("文件不能复制为目录");
}
if (!to.getParentFile().exists()) {
to.getParentFile().mkdirs(); //复制父目录
}
}
try {
BufferedReader bufr = new BufferedReader(new FileReader(from));
BufferedWriter bufw = new BufferedWriter(new FileWriter(to));
String line;
//另外开辟一个缓冲区,存储读取的一行数据,返回包含该行内容的字符串,不包含换行符,如果已到达流末尾,则返回【 null】
while ((line = bufr.readLine()) != null) {
for (String string : REPLACE_STRINGS) {
line = line.replace(string, BLANK);//替换为空格
}
bufw.write(line);
bufw.write(BLANK + BLANK);//加两个空格
bufw.newLine();// 写入一个行分隔符
bufw.flush();
}
bufr.close();
bufw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取重命名的文件名
*/
private static String getNewName(File file) {
String name = file.getName();
if (name.endsWith(SUFFIX_MD_TXT)) { //处理指定后缀的文件
name = name.substring(0, name.indexOf(SUFFIX_MD_TXT) + SUFFIX_MD.length());
} else if (name.endsWith(SUFFIX_TXT)) {
name = name.substring(0, name.indexOf(SUFFIX_TXT)) + SUFFIX_MD;
}
return name;
}
}
TOCUtils
public class TOCUtils {
private static final String HEADER_STRING = "#";
private static final char HEADER_CHAR = '#';
private static final String TOC_TITLE = "";//在目录前插入的内容
private static final String REPLACE_TOC = "[TOC]"; //目录要替换的内容
private static final String HEADER_1 = "="; //一级目录
private static final String HEADER_2 = "--"; //二级目录
private static final String SPACES = " ";
private static final String CODES = "%([abcdef]|\\d){2,2}";
private static final String SPECIAL_CHARS = "[\\/?!:\\[\\]`.,()*\"';{}+=<>~\\$|#]";
private static final String DASH = "-";
private static final String EMPTY = "";
private static final String AFFIX = "\t";
private static String ROOT_DIR = null;
/**
* 递归为为文件生成目录
*/
public static void insertToc(File from, boolean addHeader) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
} else if (ROOT_DIR == null) {
ROOT_DIR = from.getAbsolutePath();
}
if (from.isFile()) {
insertTocIntoFile(from, from, REPLACE_TOC, Integer.MAX_VALUE, addHeader);
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
insertToc(file, addHeader);//递归
} else if (file.isFile()) {
insertTocIntoFile(file, file, REPLACE_TOC, Integer.MAX_VALUE, addHeader);
}
}
}
/**
* 为文件生成目录
*/
private static void insertTocIntoFile(File from, File to, String replaceAt, int deepLevel, boolean addHeader) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(from)));
String line;//当前行的内容
String previousLine = null;
List<String> contentList = new ArrayList<>();//每一行的内容集合
List<String> titleList = new ArrayList<>();//标题集合
int currentLine = 0;
int patternLineNumber = 1; //目录插在那一行
while ((line = reader.readLine()) != null) {
++currentLine;
boolean skipLine = false;
String trimLineString = line.trim();
if (trimLineString.startsWith(HEADER_STRING)) { //检测到标题
int count = getCharCount(trimLineString, HEADER_CHAR);
if (count < 1 || count > deepLevel) { //层级控制
System.out.println("----------------------------超过最大层级 " + deepLevel);
previousLine = line;
continue;
}
String headerName = trimLineString.substring(count).trim(); //去掉层级后的文字
System.out.println("【" + headerName + "】");
titleList.add(getTitle(count, headerName));
} else if (line.startsWith(HEADER_1) && isNotEmpty(previousLine) && line.replaceAll(HEADER_1, "").isEmpty()) {
//titleList.add(getTitle(1, previousLine.trim()));//暂时不需要
} else if (line.startsWith(HEADER_2) && isNotEmpty(previousLine) && line.replaceAll(HEADER_2, "").isEmpty()) {
//titleList.add(getTitle(2, previousLine.trim()));//暂时不需要
} else if (patternLineNumber <= 1 && line.trim().equals(replaceAt)) {
patternLineNumber = currentLine; //找到这个字符串时就插在这一行(替换这个字符串),找到之后就不再继续找了
skipLine = true;//忽略这一行
}
if (!skipLine) {
contentList.add(line);
}
previousLine = line;
}
closeStream(reader); //必须先关掉这个读取,流才能开启写入流
if (patternLineNumber <= 0) {
System.out.println("----------------------------目录插入位置有误");
return;
}
contentList.add(patternLineNumber - 1, TOC_TITLE);//在指定位置插入目录前面的标题
for (String title : titleList) {
contentList.add(patternLineNumber, title);
patternLineNumber++;
}
writeFile(to, contentList, addHeader);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeStream(reader);
}
}
/**
* 写内容到指定文件
*/
private static void writeFile(File file, List<String> contentList, boolean addHeader) {
PrintWriter writer = null;
try {
writer = new PrintWriter(new FileWriter(file));
if (addHeader) {
String title = file.getName().substring(0, file.getName().indexOf(".md"));
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified()));
String bqtdir = file.getParent().substring(ROOT_DIR.length() + 1).replace("\\", "/");
writer.append("---").append("\n")//
.append("title: ").append(title).append("\n")//标题
.append("date: ").append(date).append("\n")//生成日期
.append("bqtdir: ").append(bqtdir).append("\n")//自定义路径
.append("categories:").append("\n");//分类
for (String dir : bqtdir.split("/")) {
writer.append(" - ").append(dir).append("\n");//路径分类
}
writer.append("---").append("\n").append("\n");
}
for (String string : contentList) {
writer.append(string).append("\n");
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeStream(writer);
}
}
/**
* 关闭流
*/
private static void closeStream(Closeable... closeable) {
for (Closeable c : closeable) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 判断字符串非空
*/
private static boolean isNotEmpty(String string) {
return string != null && !string.isEmpty();
}
/**
* 计算字符串中字符的个数
*/
private static int getCharCount(String string, char c) {
int count = 0;
for (int i = 0; i < string.length(); i++) {
if (string.charAt(i) == c) {
++count;
} else {
break;
}
}
return count;
}
/**
* 插入的目录的模型
*/
private static String getTitle(int deepLevel, String headerName) {
StringBuilder title = new StringBuilder();
if (deepLevel > 1) {
for (int i = 0; i < deepLevel - 1; i++) {
title.append(AFFIX);
}
}
String headerLink = headerName.trim()//
.replaceAll(SPACES, DASH)//替换特殊字符,比如必须将空格换成'-'
.replaceAll(CODES, EMPTY)//
.replaceAll(SPECIAL_CHARS, EMPTY).toLowerCase();
title.append(DASH).append(SPACES)//格式为【%s- [%s](#%s)】或【缩进- [标题][#链接]】
.append("[").append(headerName).append("]")//
.append("(").append("#")//
.append(headerLink)//
.append(")");
return title.toString();
}
}
DirUtils
public class DirUtils {
private static final String WEBSITE = "https://github.com/baiqiantao/MyAndroidBlogs/blob/master/";
private static final String SPACE = " ";
private static final String SPACE_FORMAT = "%20";
private static final String[] EXCLUDE_FILES = new String[] { ".git", "README.md" };
private static final String SUFFIX_MD = ".md";
/**
* 获取指定目录及其子目录下的文件的文件名,并对文件名进行格式化,并存储到一个指定的集合中,并将内容复制到粘贴板
*/
public static List<String> getFormatFilesNames(File from) {
List<String> filePathList = new ArrayList<>();
getDirFormatFilesNames(filePathList, from, 0);
StringBuilder sBuilder = new StringBuilder();
for (String string : filePathList) {
System.out.print(string);
sBuilder.append(string);
}
setSysClipboardText(sBuilder.toString());
return filePathList;
}
/**
* 获取指定目录及其子目录下的文件的文件名,并对文件名进行格式化,并存储到一个指定的集合中
*
* @param filePathList 将结果保存到指定的集合中
* @param from 要遍历的目录
* @param curLeval 记录当前递归所在层级
*/
private static void getDirFormatFilesNames(List<String> filePathList, File from, int curLeval) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
} else if (isExcludeFile(from.getName())) {
System.out.println("----------------------" + "忽略文件" + from.getName());
return;
} else {
filePathList = filePathList == null ? new ArrayList<String>() : filePathList;
filePathList.add(getTitle(curLeval, from));
}
curLeval++;
File[] files = from.listFiles();
if (files == null || files.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
return;
}
for (File file : files) {
if (file.isDirectory()) {
getDirFormatFilesNames(filePathList, file, curLeval);//递归
} else if (file.isFile() && !isExcludeFile(file.getName())) {
filePathList.add(getTitle(curLeval, file));
}
}
}
/**
* 是否是忽略的文件
*/
private static boolean isExcludeFile(String fileName) {
for (String name : EXCLUDE_FILES) {
if (name.equals(fileName)) {
return true;
}
}
return false;
}
/**
* 将字符串复制到剪切板
*/
private static void setSysClipboardText(String writeMe) {
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable tText = new StringSelection(writeMe);
clip.setContents(tText, null);
}
/***
* 格式化目录
*/
private static String getTitle(int level, File file) {
StringBuilder sb = new StringBuilder();
StringBuilder parentPath = new StringBuilder();
File parent = file;
for (int x = 1; x < level; x++) {
sb.append("\t");
parent = parent.getParentFile();//逐级获取父文件
parentPath.insert(0, parent.getName() + "/");//在前面插入父文件的文件名
}
sb.append("-").append(" ")//无序列表
.append("[")//超链接显示的字符
.append(file.getName().endsWith(SUFFIX_MD) ? file.getName().substring(0, file.getName().lastIndexOf(SUFFIX_MD)) : file.getName())//
.append("]")//
.append("(")//拼接超链接
.append(WEBSITE)//前缀
.append(parentPath.toString())//父目录
.append(file.getName().replaceAll(SPACE, SPACE_FORMAT))//文件名
.append(")")//
.append("\n");
return sb.toString();
}
}
private static final String DIR = "D:/为知笔记导出/MyAndroidBlogs";
private static final String WEBSITE = "https://github.com/baiqiantao/MyAndroidBlogs/blob/master/";
private static final String FILTER = "MD";
private static final String SUFFIX_MD_TXT = ".md.txt";
private static final String SUFFIX_TXT = ".txt";
private static final String SUFFIX_MD = ".md";
private static final String SPACE = " ";
private static final String SPACE_FORMAT = "%20";
private static final String[] EXCLUDE_FILES = new String[]{".git", "README.md"};
private static final String[] REPLACE_STRINGS = new String[] { " " };//特殊字符
private static final String BLANK = " ";//空格
/**
* 递归修改文件后缀名并修改文件内容
*/
public static void modifyFile(File from) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
}
if (from.isFile()) {
if (from.getName().contains(FILTER)) {//只处理带指定标识的文件
copyAndModifyFileContent(from, new File(from.getParent(), getNewName(from)));
}
from.delete();//删除源文件
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
from.delete();//删除空文件夹
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
modifyFile(file);//递归
} else if (file.isFile()) {
if (file.getName().contains(FILTER)) {//只处理带指定标识的文件
copyAndModifyFileContent(file, new File(file.getParent(), getNewName(file)));
}
file.delete();
}
}
listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "的文件全部不符合要求");
from.delete();//删除空文件夹
}
}
/**
* 递归修改文件后缀名
*/
public static void modifyFileSuffix(File from) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
}
if (from.isFile()) {
if (from.getName().contains(FILTER)) {//只处理带指定标识的文件
from.renameTo(new File(from.getParent(), getNewName(from)));
} else {
from.delete();//删除源文件
}
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
from.delete();//删除空文件夹
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
modifyFileSuffix(file);//递归
} else if (file.isFile()) {
if (file.getName().contains(FILTER)) {//只处理带指定标识的文件
file.renameTo(new File(file.getParent(), getNewName(file)));
} else {
file.delete();
}
}
}
listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "的文件全部不符合要求");
from.delete();//删除空文件夹
}
}
/**
* 获取重命名的文件名
*/
private static String getNewName(File file) {
String name = file.getName();
if (name.endsWith(SUFFIX_MD_TXT)) { //处理指定后缀的文件
name = name.substring(0, name.indexOf(SUFFIX_MD_TXT) + SUFFIX_MD.length());
} else if (name.endsWith(SUFFIX_TXT)) {
name = name.substring(0, name.indexOf(SUFFIX_TXT)) + SUFFIX_MD;
}
return name;
}
/**
* 获取指定目录及其子目录下的文件的文件名,并对文件名进行格式化,并存储到一个指定的集合中,并将内容复制到粘贴板
*/
public static List<String> getFormatFilesNames(File from) {
List<String> filePathList = new ArrayList<>();
getDirFormatFilesNames(filePathList, from, 0);
StringBuilder sBuilder = new StringBuilder();
for (String string : filePathList) {
System.out.print(string);
sBuilder.append(string);
}
setSysClipboardText(sBuilder.toString());
return filePathList;
}
/**
* 递归获取指定目录及其子目录下的文件的文件名,并对文件名进行格式化,并存储到一个指定的集合中
*
* @param filePathList 将结果保存到指定的集合中
* @param from 要遍历的目录
* @param curLeval 记录当前递归所在层级
*/
private static void getDirFormatFilesNames(List<String> filePathList, File from, int curLeval) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
} else if (isExcludeFile(from.getName())) {
System.out.println("----------------------" + "忽略文件" + from.getName());
return;
} else {
filePathList = filePathList == null ? new ArrayList<String>() : filePathList;
filePathList.add(getTitle(curLeval, from));
}
curLeval++;
File[] files = from.listFiles();
if (files == null || files.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
return;
}
for (File file : files) {
if (file.isDirectory()) {
getDirFormatFilesNames(filePathList, file, curLeval);//递归
} else if (file.isFile() && !isExcludeFile(file.getName())) {
filePathList.add(getTitle(curLeval, file));
}
}
}
/**
* 判断是否是忽略的文件
*/
private static boolean isExcludeFile(String fileName) {
for (String name : EXCLUDE_FILES) {
if (name.equals(fileName)) {
return true;
}
}
return false;
}
/**
* 递归复制目录下的所有文件
*/
public static void copyFiles(File from, File to) {
if (from == null || !from.exists() || to == null) {
throw new RuntimeException("源文件或目标文件不存在");
}
if (from.equals(to)) {
System.out.println("----------------------源文件和目标文件是同一个" + from.getAbsolutePath());
}
if (from.isDirectory()) {
if (to.isFile()) {
throw new RuntimeException("目录不能复制为文件");
}
if (!to.exists()) {
to.mkdirs();//创建目录
}
} else {
if (to.isDirectory()) {
throw new RuntimeException("文件不能复制为目录");
}
copyFile(from, to);//文件的话直接复制
return;
}
File[] files = from.listFiles();
if (files == null || files.length == 0) {
System.out.println(from.getName() + "中不存在任何文件");
return;
}
for (File file : files) {
if (file.isDirectory()) {
File copyDir = new File(to, file.getName());
if (!copyDir.exists()) {
copyDir.mkdirs();
System.out.println("创建子目录\t\t" + copyDir.getAbsolutePath());
}
copyFiles(file, copyDir);//递归
} else if (file.getName().contains(FILTER)) {
copyFile(file, new File(to, file.getName()));
}
}
}
/**
* 复制一个文件或一个目录(不会递归复制目录下的文件)
*/
public static void copyFile(File from, File to) {
if (from == null || !from.exists() || to == null) {
throw new RuntimeException("源文件或目标文件不存在");
}
if (from.equals(to)) {
System.out.println("----------------------源文件和目标文件是同一个" + from.getAbsolutePath());
}
if (from.isDirectory()) {
if (to.isFile()) {
throw new RuntimeException("目录不能复制为文件");
}
if (!to.exists()) {
to.mkdirs();//创建目录
}
return; //没有下面的刘操作
} else {
if (to.isDirectory()) {
throw new RuntimeException("文件不能复制为目录");
}
if (!to.getParentFile().exists()) {
to.getParentFile().mkdirs(); //复制父目录
}
}
try {
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream(from));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream(to));
int ch;
while ((ch = bufis.read()) != -1) {
bufos.write(ch);
}
bufis.close();
bufos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 复制一个文件或目录(不会复制目录下的文件),复制的时候会修改文件中的一些内容
*/
public static void copyAndModifyFileContent(File from, File to) {
if (from == null || !from.exists() || to == null) {
throw new RuntimeException("源文件或目标文件不存在");
}
if (from.equals(to)) {
System.out.println("----------------------源文件和目标文件是同一个" + from.getAbsolutePath());
}
if (from.isDirectory()) {
if (to.isFile()) {
throw new RuntimeException("目录不能复制为文件");
}
if (!to.exists()) {
to.mkdirs();//创建目录
}
return; //没有下面的刘操作
} else {
if (to.isDirectory()) {
throw new RuntimeException("文件不能复制为目录");
}
if (!to.getParentFile().exists()) {
to.getParentFile().mkdirs(); //复制父目录
}
}
try {
BufferedReader bufr = new BufferedReader(new FileReader(from));
BufferedWriter bufw = new BufferedWriter(new FileWriter(to));
String line;
//另外开辟一个缓冲区,存储读取的一行数据,返回包含该行内容的字符串,不包含换行符,如果已到达流末尾,则返回【 null】
while ((line = bufr.readLine()) != null) {
for (String string : REPLACE_STRINGS) {
line = line.replace(string, BLANK);//替换为空格
}
bufw.write(line);
bufw.write(BLANK + BLANK);//加两个空格
bufw.newLine();// 写入一个行分隔符
bufw.flush();
}
bufr.close();
bufw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 将字符串复制到剪切板
*/
public static void setSysClipboardText(String writeMe) {
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable tText = new StringSelection(writeMe);
clip.setContents(tText, null);
}
/***
* 格式化目录
*/
private static String getTitle(int level, File file) {
StringBuilder sb = new StringBuilder();
StringBuilder parentPath = new StringBuilder();
File parent = file;
for (int x = 1; x < level; x++) {
sb.append("\t");
parent = parent.getParentFile();//逐级获取父文件
parentPath.insert(0, parent.getName() + "/");//在前面插入父文件的文件名
}
sb.append("-").append(" ")//无序列表
.append("[")//超链接显示的字符
.append(file.getName().endsWith(SUFFIX_MD) ? file.getName().substring(0, file.getName().lastIndexOf(SUFFIX_MD)) : file.getName())//
.append("]")//
.append("(")//拼接超链接
.append(WEBSITE)//前缀
.append(parentPath.toString())//父目录
.append(file.getName().replaceAll(SPACE, SPACE_FORMAT))//文件名
.append(")")//
.append("\n");
return sb.toString();
}
private static final String HEADER_STRING = "#";
private static final char HEADER_CHAR = '#';
private static final String TOC_TITLE = "";//在目录前插入的内容
private static final String REPLACE_TOC = "[TOC]"; //目录要替换的内容
private static final String HEADER_1 = "="; //一级目录
private static final String HEADER_2 = "--"; //二级目录
private static final String PATTERN = "%s- [%s](#%s)";//标题的格式
private static final String SPACES = " ";
private static final String CODES = "%([abcdef]|\\d){2,2}";
private static final String SPECIAL_CHARS = "[\\/?!:\\[\\]`.,()*\"';{}+=<>~\\$|#]";
private static final String DASH = "-";
private static final String EMPTY = "";
private static final String AFFIX = "\t";
/**
* 递归为文件生成Markdown目录
*/
public static void insertToc(File from) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
}
if (from.isFile()) {
insertTocIntoFile(from, from, REPLACE_TOC, Integer.MAX_VALUE);
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
insertToc(file);//递归
} else if (file.isFile()) {
insertTocIntoFile(file, file, REPLACE_TOC, Integer.MAX_VALUE);
}
}
}
/**
* 为文件生成Markdown目录
*/
public static void insertTocIntoFile(File from, File to, String replaceAt, int deepLevel) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(from)));
String line;//当前行的内容
String previousLine = null;
List<String> contentList = new ArrayList<>();//每一行的内容集合
List<String> titleList = new ArrayList<>();//标题集合
int currentLine = 0;
int patternLineNumber = 1; //目录插在那一行
while ((line = reader.readLine()) != null) {
++currentLine;
boolean skipLine = false;
String trimLineString = line.trim();
if (trimLineString.startsWith(HEADER_STRING)) { //检测到标题
int count = getCharCount(trimLineString, HEADER_CHAR);
if (count < 1 || count > deepLevel) { //层级控制
System.out.println("----------------------------超过最大层级 " + deepLevel);
previousLine = line;
continue;
}
String headerName = trimLineString.substring(count).trim(); //去掉层级后的文字
titleList.add(getTitle(count, headerName));
} else if (line.startsWith(HEADER_1) && isNotEmpty(previousLine) && line.replaceAll(HEADER_1, "").isEmpty()) {
titleList.add(getTitle(1, previousLine));
} else if (line.startsWith(HEADER_2) && isNotEmpty(previousLine) && line.replaceAll(HEADER_2, "").isEmpty()) {
titleList.add(getTitle(2, previousLine));
} else if (patternLineNumber <= 1 && line.trim().equals(replaceAt)) {
patternLineNumber = currentLine; //找到这个字符串时就插在这一行(替换这个字符串),找到之后就不再继续找了
skipLine = true;//忽略这一行
}
if (!skipLine) {
contentList.add(line);
}
previousLine = line;
}
closeStream(reader); //必须先关掉这个读取,流才能开启写入流
if (patternLineNumber <= 0) {
System.out.println("----------------------------目录插入位置有误");
return;
}
contentList.add(patternLineNumber - 1, TOC_TITLE);//在指定位置插入目录前面的标题
for (String title : titleList) {
contentList.add(patternLineNumber, title);
patternLineNumber++;
}
writeFile(to, contentList);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeStream(reader);
}
}
/**
* 写内容到指定文件
*/
private static void writeFile(File to, List<String> contentList) {
PrintWriter writer = null;
try {
writer = new PrintWriter(new FileWriter(to));
for (String string : contentList) {
writer.append(string).append("\n");
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeStream(writer);
}
}
/**
* 插入的目录的模型
*/
private static String getTitle(int deepLevel, String headerName) {
StringBuilder title = new StringBuilder();
if (deepLevel > 1) {
for (int i = 0; i < deepLevel - 1; i++) {
title.append(AFFIX);
}
}
String headerLink = headerName.trim()//
.replaceAll(SPACES, DASH)//替换特殊字符,比如必须将空格换成'-'
.replaceAll(CODES, EMPTY)//
.replaceAll(SPECIAL_CHARS, EMPTY).toLowerCase();
title.append(DASH).append(SPACES)//格式为【%s- [%s](#%s)】或【缩进- [标题][#链接]】
.append("[").append(headerName).append("]")//
.append("(").append("#")//
.append(headerLink)//
.append(")");
return title.toString();
}
/**
* 关闭流
*/
public static void closeStream(Closeable... closeable) {
for (Closeable c : closeable) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 计算字符串中字符的个数
*/
private static int getCharCount(String string, char c) {
int count = 0;
for (int i = 0; i < string.length(); i++) {
if (string.charAt(i) == c) {
++count;
} else {
break;
}
}
return count;
}
/**
* 获取文件行数
*/
public static int getFileLines(File file) {
LineNumberReader reader = null;
try {
reader = new LineNumberReader(new FileReader(file));
reader.skip(Long.MAX_VALUE);
return reader.getLineNumber() + 1;
} catch (IOException ignored) {
} finally {
closeStream(reader);
}
return -1;
}
/**
* 判断字符串非空
*/
public static boolean isNotEmpty(String string) {
return string != null && !string.isEmpty();
}
MDUtils
public class MDUtils {
private static final String FILTER = "MD";
private static final String SUFFIX_MD_TXT = ".md.txt";
private static final String SUFFIX_TXT = ".txt";
private static final String SUFFIX_MD = ".md";
private static final String[] REPLACE_STRINGS = new String[] { " " };//特殊字符
private static final String BLANK = " ";//空格
/**
* 递归修改文件后缀名并修改文件内容
*/
public static void modifyFile(File from) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
}
if (from.isFile()) {
if (from.getName().contains(FILTER)) {//只处理带指定标识的文件
copyAndModifyFileContent(from, new File(from.getParent(), getNewName(from)));
}
from.delete();//删除源文件
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
from.delete();//删除空文件夹
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
modifyFile(file);//递归
} else if (file.isFile()) {
if (file.getName().contains(FILTER)) {//只处理带指定标识的文件
copyAndModifyFileContent(file, new File(file.getParent(), getNewName(file)));
}
file.delete();
}
}
listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "的文件全部不符合要求");
from.delete();//删除空文件夹
}
}
/**
* 复制一个文件或目录(不会复制目录下的文件),复制的时候会修改文件中的一些内容
*/
private static void copyAndModifyFileContent(File from, File to) {
if (from == null || !from.exists() || to == null) {
throw new RuntimeException("源文件或目标文件不存在");
}
if (from.equals(to)) {
System.out.println("----------------------源文件和目标文件是同一个" + from.getAbsolutePath());
}
if (from.isDirectory()) {
if (to.isFile()) {
throw new RuntimeException("目录不能复制为文件");
}
if (!to.exists()) {
to.mkdirs();//创建目录
}
return; //没有下面的刘操作
} else {
if (to.isDirectory()) {
throw new RuntimeException("文件不能复制为目录");
}
if (!to.getParentFile().exists()) {
to.getParentFile().mkdirs(); //复制父目录
}
}
try {
BufferedReader bufr = new BufferedReader(new FileReader(from));
BufferedWriter bufw = new BufferedWriter(new FileWriter(to));
String line;
//另外开辟一个缓冲区,存储读取的一行数据,返回包含该行内容的字符串,不包含换行符,如果已到达流末尾,则返回【 null】
while ((line = bufr.readLine()) != null) {
for (String string : REPLACE_STRINGS) {
line = line.replace(string, BLANK);//替换为空格
}
bufw.write(line);
bufw.write(BLANK + BLANK);//加两个空格
bufw.newLine();// 写入一个行分隔符
bufw.flush();
}
bufr.close();
bufw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取重命名的文件名
*/
private static String getNewName(File file) {
String name = file.getName();
if (name.endsWith(SUFFIX_MD_TXT)) { //处理指定后缀的文件
name = name.substring(0, name.indexOf(SUFFIX_MD_TXT) + SUFFIX_MD.length());
} else if (name.endsWith(SUFFIX_TXT)) {
name = name.substring(0, name.indexOf(SUFFIX_TXT)) + SUFFIX_MD;
}
return name;
}
}
TOCUtils
public class TOCUtils {
private static final String HEADER_STRING = "#";
private static final char HEADER_CHAR = '#';
private static final String TOC_TITLE = "";//在目录前插入的内容
private static final String REPLACE_TOC = "[TOC]"; //目录要替换的内容
private static final String HEADER_1 = "="; //一级目录
private static final String HEADER_2 = "--"; //二级目录
private static final String SPACES = " ";
private static final String CODES = "%([abcdef]|\\d){2,2}";
private static final String SPECIAL_CHARS = "[\\/?!:\\[\\]`.,()*\"';{}+=<>~\\$|#]";
private static final String DASH = "-";
private static final String EMPTY = "";
private static final String AFFIX = "\t";
private static String ROOT_DIR = null;
/**
* 递归为为文件生成目录
*/
public static void insertToc(File from, boolean addHeader) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
} else if (ROOT_DIR == null) {
ROOT_DIR = from.getAbsolutePath();
}
if (from.isFile()) {
insertTocIntoFile(from, from, REPLACE_TOC, Integer.MAX_VALUE, addHeader);
return;
}
File[] listFiles = from.listFiles();
if (listFiles == null || listFiles.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
return;
}
for (File file : listFiles) {
if (file.isDirectory()) {
insertToc(file, addHeader);//递归
} else if (file.isFile()) {
insertTocIntoFile(file, file, REPLACE_TOC, Integer.MAX_VALUE, addHeader);
}
}
}
/**
* 为文件生成目录
*/
private static void insertTocIntoFile(File from, File to, String replaceAt, int deepLevel, boolean addHeader) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(from)));
String line;//当前行的内容
String previousLine = null;
List<String> contentList = new ArrayList<>();//每一行的内容集合
List<String> titleList = new ArrayList<>();//标题集合
int currentLine = 0;
int patternLineNumber = 1; //目录插在那一行
while ((line = reader.readLine()) != null) {
++currentLine;
boolean skipLine = false;
String trimLineString = line.trim();
if (trimLineString.startsWith(HEADER_STRING)) { //检测到标题
int count = getCharCount(trimLineString, HEADER_CHAR);
if (count < 1 || count > deepLevel) { //层级控制
System.out.println("----------------------------超过最大层级 " + deepLevel);
previousLine = line;
continue;
}
String headerName = trimLineString.substring(count).trim(); //去掉层级后的文字
System.out.println("【" + headerName + "】");
titleList.add(getTitle(count, headerName));
} else if (line.startsWith(HEADER_1) && isNotEmpty(previousLine) && line.replaceAll(HEADER_1, "").isEmpty()) {
//titleList.add(getTitle(1, previousLine.trim()));//暂时不需要
} else if (line.startsWith(HEADER_2) && isNotEmpty(previousLine) && line.replaceAll(HEADER_2, "").isEmpty()) {
//titleList.add(getTitle(2, previousLine.trim()));//暂时不需要
} else if (patternLineNumber <= 1 && line.trim().equals(replaceAt)) {
patternLineNumber = currentLine; //找到这个字符串时就插在这一行(替换这个字符串),找到之后就不再继续找了
skipLine = true;//忽略这一行
}
if (!skipLine) {
contentList.add(line);
}
previousLine = line;
}
closeStream(reader); //必须先关掉这个读取,流才能开启写入流
if (patternLineNumber <= 0) {
System.out.println("----------------------------目录插入位置有误");
return;
}
contentList.add(patternLineNumber - 1, TOC_TITLE);//在指定位置插入目录前面的标题
for (String title : titleList) {
contentList.add(patternLineNumber, title);
patternLineNumber++;
}
writeFile(to, contentList, addHeader);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeStream(reader);
}
}
/**
* 写内容到指定文件
*/
private static void writeFile(File file, List<String> contentList, boolean addHeader) {
PrintWriter writer = null;
try {
writer = new PrintWriter(new FileWriter(file));
if (addHeader) {
String title = file.getName().substring(0, file.getName().indexOf(".md"));
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified()));
String bqtdir = file.getParent().substring(ROOT_DIR.length() + 1).replace("\\", "/");
writer.append("---").append("\n")//
.append("title: ").append(title).append("\n")//标题
.append("date: ").append(date).append("\n")//生成日期
.append("bqtdir: ").append(bqtdir).append("\n")//自定义路径
.append("categories:").append("\n");//分类
for (String dir : bqtdir.split("/")) {
writer.append(" - ").append(dir).append("\n");//路径分类
}
writer.append("---").append("\n").append("\n");
}
for (String string : contentList) {
writer.append(string).append("\n");
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeStream(writer);
}
}
/**
* 关闭流
*/
private static void closeStream(Closeable... closeable) {
for (Closeable c : closeable) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 判断字符串非空
*/
private static boolean isNotEmpty(String string) {
return string != null && !string.isEmpty();
}
/**
* 计算字符串中字符的个数
*/
private static int getCharCount(String string, char c) {
int count = 0;
for (int i = 0; i < string.length(); i++) {
if (string.charAt(i) == c) {
++count;
} else {
break;
}
}
return count;
}
/**
* 插入的目录的模型
*/
private static String getTitle(int deepLevel, String headerName) {
StringBuilder title = new StringBuilder();
if (deepLevel > 1) {
for (int i = 0; i < deepLevel - 1; i++) {
title.append(AFFIX);
}
}
String headerLink = headerName.trim()//
.replaceAll(SPACES, DASH)//替换特殊字符,比如必须将空格换成'-'
.replaceAll(CODES, EMPTY)//
.replaceAll(SPECIAL_CHARS, EMPTY).toLowerCase();
title.append(DASH).append(SPACES)//格式为【%s- [%s](#%s)】或【缩进- [标题][#链接]】
.append("[").append(headerName).append("]")//
.append("(").append("#")//
.append(headerLink)//
.append(")");
return title.toString();
}
}
DirUtils
public class DirUtils {
private static final String WEBSITE = "https://github.com/baiqiantao/MyAndroidBlogs/blob/master/";
private static final String SPACE = " ";
private static final String SPACE_FORMAT = "%20";
private static final String[] EXCLUDE_FILES = new String[] { ".git", "README.md" };
private static final String SUFFIX_MD = ".md";
/**
* 获取指定目录及其子目录下的文件的文件名,并对文件名进行格式化,并存储到一个指定的集合中,并将内容复制到粘贴板
*/
public static List<String> getFormatFilesNames(File from) {
List<String> filePathList = new ArrayList<>();
getDirFormatFilesNames(filePathList, from, 0);
StringBuilder sBuilder = new StringBuilder();
for (String string : filePathList) {
System.out.print(string);
sBuilder.append(string);
}
setSysClipboardText(sBuilder.toString());
return filePathList;
}
/**
* 获取指定目录及其子目录下的文件的文件名,并对文件名进行格式化,并存储到一个指定的集合中
*
* @param filePathList 将结果保存到指定的集合中
* @param from 要遍历的目录
* @param curLeval 记录当前递归所在层级
*/
private static void getDirFormatFilesNames(List<String> filePathList, File from, int curLeval) {
if (from == null || !from.exists()) {
throw new RuntimeException("源目录或文件不存在");
} else if (isExcludeFile(from.getName())) {
System.out.println("----------------------" + "忽略文件" + from.getName());
return;
} else {
filePathList = filePathList == null ? new ArrayList<String>() : filePathList;
filePathList.add(getTitle(curLeval, from));
}
curLeval++;
File[] files = from.listFiles();
if (files == null || files.length == 0) {
System.out.println("----------------------" + from.getName() + "中不存在任何文件");
return;
}
for (File file : files) {
if (file.isDirectory()) {
getDirFormatFilesNames(filePathList, file, curLeval);//递归
} else if (file.isFile() && !isExcludeFile(file.getName())) {
filePathList.add(getTitle(curLeval, file));
}
}
}
/**
* 是否是忽略的文件
*/
private static boolean isExcludeFile(String fileName) {
for (String name : EXCLUDE_FILES) {
if (name.equals(fileName)) {
return true;
}
}
return false;
}
/**
* 将字符串复制到剪切板
*/
private static void setSysClipboardText(String writeMe) {
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable tText = new StringSelection(writeMe);
clip.setContents(tText, null);
}
/***
* 格式化目录
*/
private static String getTitle(int level, File file) {
StringBuilder sb = new StringBuilder();
StringBuilder parentPath = new StringBuilder();
File parent = file;
for (int x = 1; x < level; x++) {
sb.append("\t");
parent = parent.getParentFile();//逐级获取父文件
parentPath.insert(0, parent.getName() + "/");//在前面插入父文件的文件名
}
sb.append("-").append(" ")//无序列表
.append("[")//超链接显示的字符
.append(file.getName().endsWith(SUFFIX_MD) ? file.getName().substring(0, file.getName().lastIndexOf(SUFFIX_MD)) : file.getName())//
.append("]")//
.append("(")//拼接超链接
.append(WEBSITE)//前缀
.append(parentPath.toString())//父目录
.append(file.getName().replaceAll(SPACE, SPACE_FORMAT))//文件名
.append(")")//
.append("\n");
return sb.toString();
}
}
2018-10-24
生成Markdown目录 字符串解析 MD的更多相关文章
- ADO.NET生成的数据库连接字符串解析
1.概述 当我们使用ADO.NET数据实体模型生成的时候,在项目目下生成一个.edmx文件的同时,还会在app.config里面出现如下一个代码串: <?xml version="1. ...
- git - gitHub生成Markdown目录
就是github-markdown-toc.go. github-markdown-toc.go Github地址 如果你有GO语言(又是你)的编译环境,可以尝试自己编译,如果没有,可以直接下载编译好 ...
- C#实现生成Markdown文档目录树
前言 之前我写了一篇关于C#处理Markdown文档的文章:C#解析Markdown文档,实现替换图片链接操作 算是第一次尝试使用C#处理Markdown文档,然后最近又把博客网站的前台改了一下,目前 ...
- [Selenium2+python2.7][Scrap]爬虫和selenium方式下拉滚动条获取简书作者目录并且生成Markdown格式目录
预计阅读时间: 15分钟 环境: win7 + Selenium2.53.6+python2.7 +Firefox 45.2 (具体配置参考 http://www.cnblogs.com/yoyok ...
- InfluxDB源码目录结构解析
操作系统 : CentOS7.3.1611_x64 go语言版本:1.8.3 linux/amd64 InfluxDB版本:1.1.0 influxdata主目录结构 [root@localhost ...
- 基于开源库jsoncpp的json字符串解析
json(JavaScript Object Notation)是一种轻量级高效数据交换格式.相比于XML,其更加简洁,解析更加方便.在实习期间,我负责的程序模块,多次使用到json进行数据传输.由于 ...
- NET 5.0 Swagger API 自动生成MarkDown文档
目录 1.SwaggerDoc引用 主要接口 接口实现 2.Startup配置 注册SwaggerDoc服务 注册Swagger服务 引用Swagger中间件 3.生成MarkDown 4.生成示例 ...
- Markdown 目录
Markdown 目录 1. TOC TOC 全称为 Table of Content,自动列出全部标题. 用法: [toc] 在 Markdown 中,自动生成目录非常简单,只需要在恰当的位置添加 ...
- 好用的Markdown编辑器一览 readme.md 编辑查看
https://github.com/pandao/editor.md https://pandao.github.io/editor.md/examples/index.html Editor.md ...
随机推荐
- Windows 7 MBR的修复与Linux产品正确卸载
这几天折腾系统很令人崩溃,但也明白了开机引导流程具体如何. 觉得Centos 7不好用,想卸载Redhat安装Ubuntu,为了图方便直接把红帽的硬盘区格式化了.于是开机引导崩溃,咨询了下大神,大神叫 ...
- Java之多线程 Atomic(原子的)
一.何谓Atomic? Atomic一词跟原子有点关系,后者曾被人认为是最小物质的单位.计算机中的Atomic是指不能分割成若干部分的意思.如果一段代码被认为是Atomic,则表示这段代码在执行过程中 ...
- Ulipad安装、配置使用教程(附Ulipad下载)
一.安装Ulipad 因为ulipad编辑器使用的是wxpython编写的gui,所以我们需要第三方库wxpython的支持,这里我们先讲一下Ulipad在Windows系统环境下的安装: 1. 确实 ...
- [原创]Jmeter工具学习思维导图
[原创]Jmeter工具学习思维导图
- Data transfer from GPIO port to RAM buffer using DMA upon receiving a trigger signal on the timer capture input channel.
Data transfer from GPIO port to RAM buffer using DMA upon receiving a trigger signal on the timer ca ...
- TFS分布式文件系统
简介 TFS(Taobao !FileSystem)是一个高可扩展.高可用.高性能.面向互联网服务的分布式文件系统,主要针对海量的非结构化数据,它构筑在普通的Linux机器集群上,可为外部提供高可靠和 ...
- React和Vue特性和书写差异
Vue均使用ES6语法,主要以单文件组件为例,写法上优先使用缩写. React使用TS语法. 生命周期 Vue React 入口&根实例 Vue const app = new Vue({ / ...
- AngularJS使用angular-formly进行表单验证
当验证表单中有很多字段时,这时候可能希望把html的生成以及验证逻辑放到controller中,在页面,也许是这样的: <some-form fiedls="vm.someFields ...
- redis实现异步任务队列
redis实现异步任务队列 先说思路: 将任务对象序列为JSON字符串,然后推入REDIS缓存,这叫入队. 通过独立的工作线程从REDIS拉出一个任务,这叫出队,工作线程将JSON字符串还原为任务对象 ...
- rTorrent + ruTorrent 安装和配置
原文地址:http://wangyan.org/blog/rtorrent-and-rutorrent-tutorial.html rTorrent 是一款非常简洁优秀的BT客户端,它完全基于文本并可 ...