生成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 ...
随机推荐
- Django(request和response)
原文链接: https://blog.csdn.net/weixin_31449201/article/details/81043326 Django中的请求与响应 一.请求request djang ...
- Shape流动效果
<Window x:Class="MvvmLight1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/ ...
- Codechef September Challenge 2018 游记
Codechef September Challenge 2018 游记 Magician versus Chef 题目大意: 有一排\(n(n\le10^5)\)个格子,一开始硬币在第\(x\)个格 ...
- zoj 3644 记忆化搜索
题目:给出一个有向图,从1到n,每个结点有个权值,每走一步,分值为结点权值的LCM,而且每一步的LCM都要有变化,问到达N的时候分值恰好为K的路径有多少条 记忆化搜索,虽然做过很多了,但是一直比较慢, ...
- css基础 行内元素 块级元素
1.行内元素(内联元素 inlineElement) 特点:不占据一行,无法设置宽高及行高,其宽度随着内容增加,高度随字体大小而改变,margin只对左右起作用,上下无效. 常见有: a - 锚点,b ...
- B+/-Tree原理
B-Tree介绍 B-Tree是一种多路搜索树(并不是二叉的): 1.定义任意非叶子结点最多只有M个儿子:且M>2: 2.根结点的儿子数为[2, M]: 3. ...
- 在mysql中使用group by和order by取每个分组中日期最大一行数据
转载自:https://blog.csdn.net/shiyong1949/article/details/78482737 在mysql中使用group by进行分组后取某一列的最大值,我们可以直接 ...
- Kruskal 模板
最小生成树指的是在图上面找到权值最小的一棵树,并且保证图上所有的点都在这棵树上. 解决办法:Kruskal 算法(贪心思想) 将边按权值从小到大排序,然后按这个顺序不断连边,直到所有点联通. /** ...
- Oracle初始化参数之memory_target
一.引言: Oracle 9i引入pga_aggregate_target,可以自动对PGA进行调整: Oracle 10g引入sga_target,可以自动对SGA进行调整: Oracle 11g则 ...
- STM32 F4 SPI Accelerometer
STM32 F4 SPI Accelerometer