批量生成小说索引以及更改一些图片名称
最近在做一款小说阅读的软件 ,需要嵌入很多小说,而且要生成相应的目录和更改图片名称,手动处理会很无聊,也很容易出
错。作为程序猿应该不会做这种无聊透顶的事。
遂就写了一个批量生成目录和更改图片名称的一个程序。
每一本小说文件都在其文件夹中。请见下图
上图是盗墓修仙记文件夹中的情况,每一本小说都是这样子, 两张图和一个txt文件放在一个文件夹中,每一本小说文件夹中
里面文件名都一样 都是三样名称ico conver main.txt,其中图片的后缀可以为其他,不一定非要跟上图一样。
然后下面是我截取其中一个处理后的小说文件夹的截图 多了一个文件 content.txt 这是程序生成的,另外图片的名称也改了
content.txt文件里面内容是这样 这只是content的一部分
本程序主要难点是怎么生成小说目录。
本人在程序截取目录时毫无疑问用了正则表达式,因为小说的目录是不总是一样的,
好了 不罗嗦了额 下面是本次的代码,可能有些bug,但我在用的时候没什么问题,如你要用可以copy到eclipse建一个java项目直接
用,copy的同时,程序中程序可根据需要来修改其中部分(如路径,正则等等)。在此声明下,如用此代码给您文件造成损坏或错
乱,本人一概不负责,请谨慎使用,用的时候建议先测试一下。
下面是本次程序完整源代码 带注释
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.io.ObjectInputStream.GetField; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.management.Descriptor; /** * @author manymore13 * 创建小说的目录和每一章节的位置(按字节定位) 并以txt文档的方式显示出结果 * main.txt ico conver 在同一个目录下con,conver分别是图片的前缀 main.txt是小说文件 */ public class CreateContent { private String m_bookPath; private String m_bookName; public static List<Long> positionList; public static List<String> titileList; String m_patternString; // 换行符占两个字节 private int breakLineSize = 2; /** * * @param path 书的路径 * @param pattern 章节的正则表达式 */ public CreateContent(String path, String name, String pattern) { m_bookPath = path; m_bookName = name; m_patternString = pattern; positionList = new ArrayList<Long>(); titileList = new ArrayList<String>(); } /** * 写入文档中(txt文件),目录和位置以 字符串"/"隔开(目录和位置) * @param filePath 写出目录的路径 * @param fileName 写出目录的名称 * @throws IOException */ public void writeContentToFile(String filePath, String fileName) throws IOException { File contentFile = new File(filePath+File.separator+fileName); if((contentFile!=null) && (!contentFile.exists())) { contentFile.createNewFile(); } PrintWriter pw = new PrintWriter(contentFile); for(int i=0; i<titileList.size(); i++) { pw.println(titileList.get(i)+"/"+positionList.get(i)); } pw.flush(); pw.close(); if(titileList.size()>0) { System.out.println("目录生成成功"); }else{ System.out.println("目录生成失败"); } } /** * 解析小说文件 */ public void parseBookFile() throws RuntimeException { BufferedReader br = null; File bookFile = new File(m_bookPath+File.separator+m_bookName); if(!bookFile.exists()) { throw new RuntimeException(m_bookPath+"小说文件不存在"); } try { br = new BufferedReader(new InputStreamReader(new FileInputStream(bookFile))); } catch (FileNotFoundException e) { e.printStackTrace(); } long preByte=0L; Pattern pattern = Pattern.compile(m_patternString); String line; try { while((line = br.readLine())!=null) { Matcher matcher = pattern.matcher(line); while(matcher.find()) { int start = matcher.start(); int end = matcher.end(); String title = line.substring(start, end); int currentSize = line.substring(0, start).getBytes("GBK").length; positionList.add(preByte+currentSize+1); titileList.add(title); } preByte+=line.getBytes("GBK").length+breakLineSize; } } catch (IOException e) { e.printStackTrace(); }finally{ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } System.out.println("一共有多少字节:"+(preByte)); } /** * 获取小说文件有效行数 * @return */ public int getCountLines() { int lineSum = 0; File bookFile = new File(m_bookPath+File.separator+m_bookName); if(!bookFile.exists()) { System.out.println("小说文件不存在"); System.exit(0); } BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(new FileInputStream(bookFile))); } catch (FileNotFoundException e) { e.printStackTrace(); } try { while(br.readLine()!=null) { lineSum++; } } catch (IOException e) { e.printStackTrace(); }finally{ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } return lineSum; } //^第.+章.+$ //第[\d一二三四五六七八九十]+章\\s*.{0,20} public static void main(String[] args) { // 正则表达式 按自己需要来更改 String pattern = "第[\\d一二三四五六七八九十百千]+[章节集]\\s*.{0,20}"; // 小说主名字 我这里面都是固定的 String bookName = "main.txt"; // 要批量处理的小说根路径 String bookNamePath = "C:\\小说\\50本小说"; // 所生成的目录文件的名称 你可以更改其他的 String contentFileName = "content.txt"; File[] bookNameFiles = new File(bookNamePath).listFiles(); for(File f:bookNameFiles) { if(f.isDirectory()) { bookNamePath = f.getAbsolutePath(); }else{ continue; } startProcess(bookNamePath, bookName, contentFileName, pattern); System.out.println(); } System.out.println("一共"+bookNameFiles.length+"本小说"); } public static void startProcess(String bookNamePath,String bookName,String contentFileName,String pattern) { System.out.println("正在处理"+bookNamePath+"路径下"+"小说"); CreateContent createContent = new CreateContent(bookNamePath,bookName,pattern); createContent.initContainer(); try{ createContent.parseBookFile(); }catch(RuntimeException r){ System.out.println(r.getMessage()); return; } /*生成小说目录*/ try { createContent.writeContentToFile(bookNamePath, contentFileName); } catch (IOException e) { e.printStackTrace(); } /*更改图片名字*/ int i = createContent.changeImageName(); System.out.println("改变了"+i+"张图片"); } /** * 初始化容器 */ private void initContainer() { titileList.clear(); positionList.clear(); } /** * 修改图片文件名字前缀 icon start */ public int changeImageName() { File rootfile = new File(m_bookPath); String prefix = null; // 前缀 String postfix = null;// 后缀 int count = 0; File imageFile; File newImageFile; if(!rootfile.isDirectory()) { return 0; } /*获取该目录下图片名字*/ String[] imageNames = rootfile.list(new FileFilter()); for(String name:imageNames) { postfix = name.split("\\.")[1]; imageFile = new File(m_bookPath + File.separator + name); if(name.equals("ico"+"."+postfix)) { prefix = "icon"; }else if(name.equals("conver"+"."+postfix)){ prefix = "start"; }else{ continue; } newImageFile = new File(m_bookPath+File.separator+prefix+"."+postfix); imageFile.renameTo(newImageFile); count++; } return count; } /** * * @author manymore13 * 文件过滤器 过滤以后缀.png, .jpg的文件 */ class FileFilter implements FilenameFilter { @Override public boolean accept(File dir, String name) { return ((name.endsWith(".png"))||(name.endsWith(".jpg")))&& (new File(dir.getAbsoluteFile()+File.separator+name).isFile()); } } }
我所看到小说目录有是 有的是 第一章,有是 第一节,第1章,第1节......不管它们怎么变,你正则在你解析小说时匹配就OK,
本人在用正则解析小说文件出现OOM内存溢出的问题,正则额是解析字符串的,所以本人刚刚开始的思路是把其中一本小说一次全
部读入内存当做字符串,然后用正则扫描生成目录,结果爆OOM,StringBuilder.toString的问题 可能有大小限制。
后来果断换了一种方式,也就是现在程序中的采取的按行读取,读一行扫描一行。用这种方式也需要考虑到一个问题,一个目录只
能占一行。若占两行的话,会给目录位置上和正则匹配造成不必要的麻烦。
好像一般的小说也没有一个目录占两行的呀!我在这里只是提一提这个问题而已。
下面发一张运用本次目录的效果图