最近在做一款小说阅读的软件 ,需要嵌入很多小说,而且要生成相应的目录和更改图片名称,手动处理会很无聊,也很容易出
错。作为程序猿应该不会做这种无聊透顶的事。
遂就写了一个批量生成目录和更改图片名称的一个程序。
每一本小说文件都在其文件夹中。请见下图
上图是盗墓修仙记文件夹中的情况,每一本小说都是这样子, 两张图和一个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的问题 可能有大小限制。
后来果断换了一种方式,也就是现在程序中的采取的按行读取,读一行扫描一行。用这种方式也需要考虑到一个问题,一个目录只
能占一行。若占两行的话,会给目录位置上和正则匹配造成不必要的麻烦。
好像一般的小说也没有一个目录占两行的呀!我在这里只是提一提这个问题而已。
下面发一张运用本次目录的效果图