生成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 ...
随机推荐
- C#开发Unity游戏教程之判断语句
C#开发Unity游戏教程之判断语句 游戏执行路径的选择——判断 玩家在游戏时,无时无刻不在通过判断做出选择.例如,正是因为玩家做出的选择不同,才导致游戏朝着不同的剧情发展,因此一个玩家可以对一个游戏 ...
- python标准库--functools.partial
官方相关地址:https://docs.python.org/3.6/library/functools.html 一.简单介绍: functools模块用于高阶函数:作用于或返回其他函数的函 ...
- SPOJ.1812.LCS2(后缀自动机)
题目链接 \(Description\) 求最多10个串的LCS(最长公共子序列). \(Solution\) 类比上题,对一个串建SAM,我们可以逐串地求出其在每个节点所能匹配的最大长度mx[i]. ...
- Node.js开源应用OSN发布初始V1.0版本-见面版本
Nodejs开源应用OSN初始版本V1.0发布,请参考本操作说明文档,有任何问题请留言 Nodejs开源应用OSN发布V1.0版本: OSChina收录地址: OSC收录地址:http://www.o ...
- Xtreme8.0 - Kabloom dp
Xtreme8.0 - Kabloom 题目连接: https://www.hackerrank.com/contests/ieeextreme-challenges/challenges/kablo ...
- The STM32 SPI and FPGA communication
The STM32 SPI and FPGA communication STM32 spi bus communication SPI bus in the study, the protocol ...
- [Go] 正则表达式 示例
package main import "bytes" import "fmt" import "regexp" func main() { ...
- Android 解压zip文件
过了n多天后,当再次使用原先博客上写的那篇: Android 压缩解压zip文件 去做zip包的解压的时候,出现了原来没有发现的很多问题.首先是中文汉字问题,使用java的zip包不能很好的解决解压问 ...
- 未经处理的异常:System.Net.Sockets.SocketException: 以一种访问权限不允许的方式做了一个访问套接字的尝试
报错:未经处理的异常:System.Net.Sockets.SocketException: 以一种访问权限不允许的方式做了一个访问套接字的尝试 → 尝试以"管理员身份"运行程序, ...
- 线程中sleep方法和wait方法有什么区别?(转)
本文转自https://www.cnblogs.com/linkstar/p/6043846.html 线程中sleep方法和wait方法有什么区别? 如果你没有接触过java的多线程,那么多对于 ...