Typora图片批量迁移至指定位置(java)
一、迁移图片时请备份图片源文件和md文本
-
引用内容
-
https://blog.youkuaiyun.com/mekings13/article/details/135552433
二、处理结果图
1.单独目录处理
2.多目录递归处理
3.图片迁移前后文件比较(图片路径)
三、缺陷提示
- 提取图片使用的分隔符为  {
com.xqh.操作类.typora图片迁移.TyporaImagesMove typoraImagesMove = new com.xqh.操作类.typora图片迁移.TyporaImagesMove();
typoraImagesMove.start();
//TODO 测试方法 使用下面测试 请注释上一行代码
// typoraImagesMove.test();
}
public void start() {
String directPath = "";// typora md文件路径
String copyPrefixPath = "";// 图片复制迁移目录
// 创建Scanner对象并传入标准输入流(键盘)作为参数
Scanner scanner = new Scanner(System.in);
System.out.print("请输入需要处理的md文件目录路径:");
// 读取用户输入的字符串
String input = scanner.nextLine();
this.fileExists(input);
System.out.print("请输入图片迁移至目标的文件路径:");
String tagPath = scanner.nextLine();
System.out.print("请输入处理类型:0: 单个目录处理;1: 目录递归处理");
String typeExecute = scanner.nextLine();
scanner.close();
directPath = input;
copyPrefixPath = tagPath;
this.createImageFile(copyPrefixPath);
if("0".equals(typeExecute)){
this.singleFile(directPath, copyPrefixPath);
}else if ("1".equals(typeExecute)){
this.recursionFile(directPath, copyPrefixPath);
}else {
System.out.println("请正确输入处理类型!");
}
}
/**
* 单个目录处理
* @param directPath 目录路径
* @param copyPrefixPath 图片复制迁移目录
*/
public void singleFile(String directPath, String copyPrefixPath){
File file = new File(directPath);
if(!file.exists()){
throw new RuntimeException("源文件目录为空");
}
String[] list = file.list();
if(list.length == 0){
throw new RuntimeException("空目录");
}
for(String fileName : list){
// 只处理md文件
if (!fileName.contains(".md")){
continue;
}
this.executeFile(directPath, fileName, copyPrefixPath, null);
}
}
/**
* 递归目录处理
* @param directPath 目录路径
* @param copyPrefixPath 图片复制迁移目录
*/
public void recursionFile(String directPath, String copyPrefixPath){
File file = new File(directPath);
ArrayList<String> allFileList = new ArrayList<>();
this.getAllFileMap2(file, allFileList);
for (String absPathFile : allFileList) {
this.executeFile(null, null, copyPrefixPath, absPathFile);
}
}
/**
* 单文件处理
* @param directPath 源文件目录
* @param fileName 文件名
* @param copyPrefixPath 图片复制迁移目录
* @param absPathFile 源文件绝对路径 // 递归目录时使用此参数,单目录处理填写null,directPath、fileName填null
*/
public void executeFile(String directPath, String fileName, String copyPrefixPath, String absPathFile){
try{
String filePath = "";
if(StringUtils.isNotEmpty(absPathFile) && StringUtils.isEmpty(directPath)){
filePath = absPathFile;
int separatorIndex = absPathFile.lastIndexOf(File.separator) + 1;
fileName = absPathFile.substring(separatorIndex, absPathFile.length());
}else {
filePath = directPath + File.separator + fileName;
}
List<String> lines = this.readFile(filePath);// 将该md文件内容读取出来存进List<String>中方便后续处理
List<String> newLines = new LinkedList<>();// 建一个新的List<String>用于接受处理好的内容
for (String line : lines) {// 开始对每一行内容进行处理
// 图片md的格式是这样的:
if (StringUtils.isNotBlank(line) && line.contains("![image") ||
(StringUtils.isNotBlank(line) && line.contains("<img src="))) {// 判断此行是否存在图片
String newLine = line;
ArrayList<String> oldUrlImagesList = new ArrayList<>();// 需要替换的图片集
ArrayList<String> expiredImagesList = new ArrayList<>();// 过时图片/不存在的图片集
// ![image 默认图片格式
if(line.contains("![image")){
// 只分割typora格式的图片 ![image-
String[] split1 = line.split("!\\[image-");
for (String split2 : split1) {
int start = split2.indexOf("](");// 判断](图片格式是否存在
if(StringUtils.isEmpty(split2) || start == -1){
continue;
}
start = start + 2;
int end = split2.indexOf(")");
if(end == -1){
continue;
}
String imagesUrl = split2.substring(start, end);
// 不处理网络图片和本地file:///手写统一资源图片
if(imagesUrl.contains("https://") || imagesUrl.contains("http://") || imagesUrl.contains("file:///")){
continue;
}
if(this.existsImages(imagesUrl)){
oldUrlImagesList.add(imagesUrl);
}else{
expiredImagesList.add(imagesUrl);
}
}
}
// 调整过图片大小的处理
if(line.contains("<img src=")){
String[] split1 = line.split("<img src");
for (String split2 : split1) {
if(!split2.startsWith("=\"")){
continue;
}
String end = "\" ";
if(!split2.contains(end)){
continue;
}
int endIndex = split2.indexOf(end);
String imagesUrl = split2.substring(2, endIndex);
// 不处理网络图片和本地file:///手写统一资源图片
if(imagesUrl.contains("https://") || imagesUrl.contains("http://") || imagesUrl.contains("file:///")){
continue;
}
if(this.existsImages(imagesUrl)){
oldUrlImagesList.add(imagesUrl);
}else{
expiredImagesList.add(imagesUrl);
}
}
}
// 行图片文本替换 & 复制迁移图片
if(ObjectUtils.isNotEmpty(oldUrlImagesList)){
for (String imagesUrl : oldUrlImagesList) {
int separatorIndex = imagesUrl.lastIndexOf(File.separator) + 1;
String imagesName = imagesUrl.substring(separatorIndex, imagesUrl.length());
String newImagesUrl = copyPrefixPath + File.separator + imagesName;
newLine = newLine.replace(imagesUrl, newImagesUrl);
}
// 复制迁移图片路径
this.moveCopyImages(fileName, oldUrlImagesList, copyPrefixPath);
}
if(ObjectUtils.isNotEmpty(expiredImagesList)){
for (String imagesName : expiredImagesList) {
System.out.println("Untreated_images=> 文件:"+ fileName +" 处理异常,\n\t图片info: "+ imagesName +
" \n\t异常信息:"+ " 图片过期、图片格式不正确、无法访问(想同位置无法访问) !");
}
}
// 更新行内容
line = newLine;
}
// 将内容存进新list
newLines.add(line);
}
// 将处理好的md内容重新写进md文件中
this.writeFile(newLines, filePath);
System.out.println("Finish_file=> " + filePath + "--->" + "文件:"+ fileName +" 已处理成功");
}catch (Exception e){
System.out.println("文件:"+ fileName +" 处理异常,异常信息:"+ e.getMessage() + "");
}
}
/**
* 递归获取所有文件
* @param subFile 子文件信息
* @param allFileList ArrayList<String> allFileList 集合
*/
public void getAllFileMap2(File subFile, ArrayList<String> allFileList){
if (subFile.list().length == 0 ){
// System.out.println("递归子目录为空");
return;
}
for (File xFile : subFile.listFiles()) {
String xName = xFile.getName();
if (xFile.isFile() && xName.contains(".md")){
allFileList.add(xFile.getAbsolutePath());
continue;
}
// 递归循环文件
if(xFile.isDirectory()){
this.getAllFileMap2(xFile, allFileList);
}
}
}
/**
* 读取文件行内容
* @param filePath 路径
* @return list lineList集合
*/
public List<String> readFile(String filePath){
List<String> lines = new LinkedList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath)))
{
String lineStr;
while ((lineStr = reader.readLine())!=null) {
lines.add(lineStr);
}
}catch (Exception e){
e.printStackTrace();
}
return lines;
}
/**
* 将修改的内容写回文件
* @param lineList lineList
* @param filePath filePath 文件绝对路径
*/
public void writeFile(List<String> lineList, String filePath){
try(BufferedWriter reader = new BufferedWriter(new FileWriter(filePath))){
for (String line : lineList){
reader.write(line);
reader.newLine();
}
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 判断目录是否存在
* @param file 路径
*/
public void fileExists(String file){
File f = new File(file);
if(!f.exists()){
throw new RuntimeException("源文件目录为空");
}
}
/**
* 创建图片复制迁移目录
* @param imagesPath 路径
*/
public void createImageFile(String imagesPath){
File imagesDirect = new File(imagesPath);
try{
if (!imagesDirect.exists()){
imagesDirect.mkdirs();
}else if (!imagesDirect.isDirectory()){
imagesDirect.mkdirs();
}
}catch (Exception e){
throw new RuntimeException("目标路径输入错误,或不磁盘不存在");
}
}
/**
* 图片复制方法
* @param fileName 文件名
* @param oldUrlImagesList 源图片路径集合
* @param copyPrefixPath 图片复制迁移目标目录路径
*/
public void moveCopyImages(String fileName, ArrayList<String> oldUrlImagesList, String copyPrefixPath){
String copyImagePath = "";// 图片迁移最终位置
try{
for (String oldUrlImages : oldUrlImagesList) {
File image = new File(oldUrlImages);
copyImagePath = this.getImagesName(copyPrefixPath, oldUrlImages);
File copyPath = new File(copyImagePath);
// 将存在默认盘中的图片复制出来到 目标目录下
FileUtils.copyFile(image, copyPath, true);
}
}catch (Exception e){
System.out.println("Error_images=> 文件:"+ fileName +"处理异常,\n\t图片info: "+ copyImagePath +" \n\t异常信息:"+ e.getMessage() + "");
}
}
/**
* 获取迁移后图片的绝对路径
* @param copyPrefixPath 迁移目录路径
* @param imagesUrl 源图片路径
* @return 新图片绝对路径
*/
public String getImagesName(String copyPrefixPath, String imagesUrl){
int separatorIndex = imagesUrl.lastIndexOf(File.separator) + 1;
String imagesName = imagesUrl.substring(separatorIndex, imagesUrl.length());
String newImagesUrl = copyPrefixPath + File.separator + imagesName;
return newImagesUrl;
}
/**
* 判断图片状态是否正常
* @param imagesUrl imagesUrl
* @return boolean
*/
public boolean existsImages(String imagesUrl){
File file = new File(imagesUrl);
// 不处理网络图片
if(imagesUrl.contains("https://") || imagesUrl.contains("http://") || imagesUrl.contains("file:///")){
return false;
}
return file.exists();
}
/**
* 测试入口
*/
public void test(){
String directPath = "D:" + File.separator + "xxx";// 源文件目录
// String directPath = "D:" + File.separator + "vvv";
String copyPrefixPath = "D:" + File.separator + "im";// 图片复制迁移目录
this.createImageFile(copyPrefixPath);
//TODO 使用下面其中一个方法,注释其另一个方法= =
// this.singleFile(directPath, copyPrefixPath);// 单个目录处理
this.recursionFile(directPath, copyPrefixPath);// 递归目录处理
}
}