Java对epub电子书类型切割
Epub电子书切割
引言:由于公司存储电子书的格式是.epub。一本电子书加载的时候,如果电子书大的话,全部加载该电子书会非常的消耗时间和资源。非常的不合理。那么现在,将所有电子书按章切分。将拆分的电子书再上传至服务器,用户点击阅读电子书任何一章节,就加载该章节的数据。这里的具体逻辑不细写,主要细写如果切割电子书的过程。
准备
这里我用到了Epublib这个jar包,详细资料参考下方
maven库搜索 epublib-core ,kxml2
pom文件引入依赖
<!-- https://mvnrepository.com/artifact/nl.siegmann.epublib/epublib-core -->
<dependency>
<groupId>nl.siegmann.epublib</groupId>
<artifactId>epublib-core</artifactId>
<version>3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 -->
<dependency>
<groupId>net.sf.kxml</groupId>
<artifactId>kxml2</artifactId>
<version>2.3.0</version>
</dependency>
分析
epub电子书结构
.epub电子书是怎么的结构。我这边下载了一本。我用winrar解压看下。如下图

可以很清楚看见是由xhtml文件组成资源。关于content.opf ,toc.nxc等这些本来就是属于电子书的数据结构文件,可以自行网上查阅。
epublib中book数据结构
epub电子书抽象成epublib中的book 。epublib 中book的数据结构是怎么样子的呢,这里稍微介绍一下,网上确实资料太少了。

Resource数据结构
Resources类中又有一个HashMap,HashMap中的value为Resource,Resource的数据结构如下:

- id,href相当于Resources中那个HashMap中的key,可以找到Resource
- title 和 originalHref 表资源的名字和起始的href
- mediaType 资源的数据类型 inputEncoding 编码格式
- data 第一张图片上的.xhtml转string类型,然后再转成字节流的数据
Metadata
Book里的Metadata相当于电子书的头部,可以获取电子书的基本数据,数据结构如下:

Spine
Book中的骨架结构,用来链接Book资源文件,数据结构如下

Resource 与ResourceReference 为关联,SpineReference是ResourceReference的父类。
在设置好Resouces后一定要设置相应的Spine中的Resouce,不然电子书打开,会无法识别。
TableOfContents
Book中目录对应的数据结构。有目录的名字,目录对应的Resource,对应的数据结构如下:

实战
Demo代码如下:
/**
* @Description: 按章节切分 电子书
* @Author: ouyangkang
* @CreateDate: 2018/9/28 17:41
* @Param [url]
*/
public static void segmentation(String url){
try {
// 获取网络资源
URL urlResource = new URL(url) ;
// 打开链接
HttpURLConnection conn = (HttpURLConnection) urlResource.openConnection();
// 建立链接
conn.connect();
// 读取电子书流
EpubReader epubReader = new EpubReader();
// 获取电子书
InputStream inputStream = conn.getInputStream();
if (inputStream == null){
return;
}
if (epubReader == null){
return;
}
Book book = epubReader.readEpub(inputStream);
if (book == null){
return;
}
// 获取电子书目录
TableOfContents tableOfContents = book.getTableOfContents();
// 电子书章节封装资源
List<SpineReference> spineReferences = book.getSpine().getSpineReferences();
// 电子书 章节Id 集合
List<String> resourceIds = new ArrayList<>(16);
// 获取所有资源href
Set<String> hrefs = (Set<String>) book.getResources().getAllHrefs();
// css 资源文件
List<String> hrefCss = new ArrayList<>();
hrefs.stream().forEach(href -> {
if (href.contains(".css")){
hrefCss.add(href);
}
});
spineReferences.stream().forEach(spineReference -> {
// 获取章节Id
resourceIds.add(spineReference.getResourceId());
});
// 电子书章节资源
Resources resources = new Resources();
// 写入电子书
EpubWriter epubWriter = new EpubWriter();
resourceIds.stream().forEach(resourceId -> {
// 电子书章节
Book bookChapter = new Book();
//章节导航
Spine spine = new Spine();
if (hrefCss.size() > 0){
hrefCss.stream().forEach(href -> {
resources.add(book.getResources().getByHref(href));
});
}
nl.siegmann.epublib.domain.Resource resource = book.getResources().getById(resourceId);
resources.add(resource);
// 获取图片资源
try {
String imageData = new String(resource.getData(),"UTF-8");
// 获取图片源
List<String> imagesHrefs = getImgSrc(imageData);
//添加该章节下的图片资源
imagesHrefs.stream().forEach(imagesHref -> {
nl.siegmann.epublib.domain.Resource resourceImage = book.getResources().getByHref(imagesHref);
resources.add(resourceImage);
});
//设置电子书资源
// 设置电子书导航文件
nl.siegmann.epublib.domain.Resource tocResource = book.getResources().getById("ncx");
if (tocResource != null){
// 发现有的电子书并不存在 toc.ncx 而是以一种toc.xhtml的文件存在
if (tocResource.getHref().contains("toc.ncx")) {
spine.setTocResource(tocResource);
} else {
resources.add(tocResource);
}
}
//添加章节资源
bookChapter.setResources(resources);
// 添加该章节骨架
spine.addSpineReference(new SpineReference(book.getResources().getById(resourceId)));
bookChapter.setSpine(spine);
// 添加该书的所有目录
bookChapter.setTableOfContents(tableOfContents);
//文件写入地址
String path = "D:\\ebook\\"+resourceId+".epub";
File file = new File(path);
if (!file.getParentFile().exists()){
file.getParentFile().mkdir();
}
epubWriter.write(bookChapter, new FileOutputStream(file));
} catch (IOException e) {
e.printStackTrace();
}finally {
conn.disconnect();
}
});
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 获取img标签中的src值
* @param content
* @return
*/
public static List<String> getImgSrc(String content){
List<String> list = new ArrayList<String>();
//目前img标签标示有3种表达式
//<img alt="" src="1.jpg"/> <img alt="" src="1.jpg"></img> <img alt="" src="1.jpg">
//开始匹配content中的<img />标签
Pattern p_img = Pattern.compile("<(img|IMG|image|IMAGE)(.*?)(/>|></img>|>|></image)");
Matcher m_img = p_img.matcher(content);
boolean result_img = m_img.find();
if (result_img) {
while (result_img) {
//获取到匹配的<img />标签中的内容
String str_img = m_img.group(2);
//开始匹配<img />标签中的src
Pattern p_src = Pattern.compile("(src|SRC|href|HREF)=(\"|\')(.*?)(\"|\')");
Matcher m_src = p_src.matcher(str_img);
if (m_src.find()) {
String str_src = m_src.group(3);
if (str_src.contains("Image")){
str_src = str_src.substring(str_src.indexOf("I"),str_src.length());
}else {
str_src = str_src.substring(str_src.indexOf("i"),str_src.length());
}
list.add(str_src);
}
//结束匹配<img />标签中的src
//匹配content中是否存在下一个<img />标签,有则继续以上步骤匹配<img />标签中的src
result_img = m_img.find();
}
}
return list;
}
Java对epub电子书类型切割的更多相关文章
- Java 解析epub格式电子书,helloWorld程序,附带源程序和相关jar包
秀才坤坤出品 一.epub格式电子书 相关材料和源码均在链接中可以下载:http://pan.baidu.com/s/1bnm8YXT 包括 1.JAVA项目工程test_epub,里面包括了jar包 ...
- epub电子书--目录结构介绍
epub电子书简介 epub全称为Electronic Publication的缩写,意为:电子出版, epub于2007年9月成为国际数位出版论坛(IDPF)的正式标准,以取代旧的开放Open eB ...
- java中,字符串类型的时间数据怎样转换成date类型。
将字符串类型的时间转换成date类型可以使用SimpleDateFormat来转换,具体方法如下:1.定义一个字符串类型的时间:2.创建一个SimpleDateFormat对象并设置格式:3.最后使用 ...
- [原创开源项目]EPUBBuilder一款在线的epub电子书编辑工具
epub 感觉自己么么哒, epub书:国外最流行的电子书格式: epub电子书介绍: epub全称为Electronic Publication的缩写,意为:电子出版, epub于2007年9月成为 ...
- 详解Java 8中Stream类型的“懒”加载
在进入正题之前,我们需要先引入Java 8中Stream类型的两个很重要的操作: 中间和终结操作(Intermediate and Terminal Operation) Stream类型有两种类型的 ...
- Java笔记10-Object包装类型字符串
提纲: 1.java.lang.0bject中常用方法介绍 2.基本类型对应的包装类型的介绍 以及基本类型和包装类型之间的相互转换 3.java.lang.String 字符串处理类 java.lan ...
- Java中的Bigdecimal类型运算
Java中的Bigdecimal类型运算 双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更小的数进行运算和处理.Java在java.math包中提 供的API类BigD ...
- java获取获得Timestamp类型的当前系统时间。以及java.util.date 、java.sql.Date之间的转换
java获取取得Timestamp类型的当前系统时间java获取取得Timestamp类型的当前系统时间 格式:2010-11-04 16:19:42 方法1: Timestamp d = new T ...
- Java Hour 50 日期类型
Plan List: 1 Java 中的日期类型 2 mysql 相关 3 java code style 鉴于本问题太过普通,所以参考文章满大街都是,因此本文内容基本为转载和验证. java.sql ...
随机推荐
- boost::unique_lock和boost::lock_guard的区别
lock_guard unique_lock boost::mutex mutex; boost::unique_lock<boost::mutex> lock(mutex); std:: ...
- maven构建SSM项目
对于小型项目来说,使用默认的maven配置项目即可,可是现在分布式项目越来越多,如果巧妙的使用maven部署项目这成了关键. maven的pom.jar.war: 要正确部署得对maven的pom.w ...
- Go(02)windows环境搭建和vscode配置
之前讲述过linux环境下Go语言开发环境搭建,这次简述下windows的搭建以及vscode配置 windows环境搭建 同样去https://studygolang.com/dl下载windows ...
- linux basic ------ 多命令执行
当我们需要一次执行多个命令的时候,命令之间需要用连接符连接,不同的连接符有不同的效果.下面我们总结一下,加以区分. (1) ; 分号,没有任何逻辑关系的连接符.当多个命令用分号连接时,各命令之间的执 ...
- MySQL-->高级-->001-->MySQL备份与恢复测试
- 数据结构(三)串---KMP模式匹配算法实现及优化
KMP算法实现 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include ...
- cmd 概览---- 转
打开"运行"对话框(Win+R),输入cmd,打开控制台命令窗口... 也可以通过cmd /c 命令 和 cmd /k 命令的方式来直接运行命令 注:/c表示执行完命令后关闭cmd ...
- nmap - 网络扫描
NMap,Network Mapper 最早是Linux下的网络扫描和嗅探工具包 网络链接扫描; nmap -PT 192.168.1.1-111 # 先ping在扫描主机开放端口 nmap -O 1 ...
- 用Java构建一个简单的WebSocket聊天项目之新增HTTP接口调度
采用框架 我们整个Demo基本不需要大家花费太多时间,就可以实现以下的功能. 用户token登录校验 自我聊天 点对点聊天 群聊 获取在线用户数与用户标签列表 发送系统通知 首先,我们需要介绍一下我们 ...
- C# 文件Copy
文件Copy有以下几种方法: 1.Copy string sourceFile = @"c:\temp\New Text Document.txt"; string destina ...