Epub电子书切割

引言:由于公司存储电子书的格式是.epub。一本电子书加载的时候,如果电子书大的话,全部加载该电子书会非常的消耗时间和资源。非常的不合理。那么现在,将所有电子书按章切分。将拆分的电子书再上传至服务器,用户点击阅读电子书任何一章节,就加载该章节的数据。这里的具体逻辑不细写,主要细写如果切割电子书的过程。

准备

这里我用到了Epublib这个jar包,详细资料参考下方

epublib github

epublib API

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的数据结构如下:

  1. id,href相当于Resources中那个HashMap中的key,可以找到Resource
  2. title 和 originalHref 表资源的名字和起始的href
  3. mediaType 资源的数据类型 inputEncoding 编码格式
  4. 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电子书类型切割的更多相关文章

  1. Java 解析epub格式电子书,helloWorld程序,附带源程序和相关jar包

    秀才坤坤出品 一.epub格式电子书 相关材料和源码均在链接中可以下载:http://pan.baidu.com/s/1bnm8YXT 包括 1.JAVA项目工程test_epub,里面包括了jar包 ...

  2. epub电子书--目录结构介绍

    epub电子书简介 epub全称为Electronic Publication的缩写,意为:电子出版, epub于2007年9月成为国际数位出版论坛(IDPF)的正式标准,以取代旧的开放Open eB ...

  3. java中,字符串类型的时间数据怎样转换成date类型。

    将字符串类型的时间转换成date类型可以使用SimpleDateFormat来转换,具体方法如下:1.定义一个字符串类型的时间:2.创建一个SimpleDateFormat对象并设置格式:3.最后使用 ...

  4. [原创开源项目]EPUBBuilder一款在线的epub电子书编辑工具

    epub 感觉自己么么哒, epub书:国外最流行的电子书格式: epub电子书介绍: epub全称为Electronic Publication的缩写,意为:电子出版, epub于2007年9月成为 ...

  5. 详解Java 8中Stream类型的“懒”加载

    在进入正题之前,我们需要先引入Java 8中Stream类型的两个很重要的操作: 中间和终结操作(Intermediate and Terminal Operation) Stream类型有两种类型的 ...

  6. Java笔记10-Object包装类型字符串

    提纲: 1.java.lang.0bject中常用方法介绍 2.基本类型对应的包装类型的介绍 以及基本类型和包装类型之间的相互转换 3.java.lang.String 字符串处理类 java.lan ...

  7. Java中的Bigdecimal类型运算

    Java中的Bigdecimal类型运算 双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更小的数进行运算和处理.Java在java.math包中提 供的API类BigD ...

  8. java获取获得Timestamp类型的当前系统时间。以及java.util.date 、java.sql.Date之间的转换

    java获取取得Timestamp类型的当前系统时间java获取取得Timestamp类型的当前系统时间 格式:2010-11-04 16:19:42 方法1: Timestamp d = new T ...

  9. Java Hour 50 日期类型

    Plan List: 1 Java 中的日期类型 2 mysql 相关 3 java code style 鉴于本问题太过普通,所以参考文章满大街都是,因此本文内容基本为转载和验证. java.sql ...

随机推荐

  1. spring task 实现定时执行(补充:解决定时任务执行2次问题)

    首先在spring-mvc.xml配置头文件引入: xmlns:task="http://www.springframework.org/schema/task" 其次引入task ...

  2. IE盒模型和W3C盒子模型的区别

    其实这个问题到现在真的是没有意义了,因为早在IE6的兼容模式开始就已经弃用了IE盒子模型了,但是现在的各种面试题还是会时常出现这样的上世纪的题目,我觉得其实时纯粹的刁难. 好了,吐槽不多说了,直接上图 ...

  3. WEB前端技巧之JQuery为动态添加的元素绑定事件.md

      jquery 为动态添加的元素绑定事件 如果直接写click函数的话,只能把事件绑定在已经存在的元素上,不能绑定在动态添加的元素上 可以用delegate来实现 .delegate( select ...

  4. [转载]JavaScript 的轻框架开发

    http://www.open-open.com/news/view/1d64fed 为什么我们不用 Angular, Ember 或者 Backbone! Muut 是一个特殊的论坛平台,它也有着巨 ...

  5. 【51Nod】1920 空间统计学 状压DP

    [题目]1920 空间统计学 [题意]给定m维空间中的n个点坐标,满足每一维坐标大小都在[0,3]之间,现在对于[0,3*m]的每个数字x统计曼哈顿距离为x的有序点对数.\(n \leq 2*10^5 ...

  6. 第9月第26天 pairs和ipairs cocos2dx 动画

    1. a={ ip = "127.0.0.1", port = 6789 } for i,v in pairs(a) do print(i,v) end a={1} for i,v ...

  7. centos7,php7 安装mysqli扩展

    首先安装MySQL https://www.cnblogs.com/manzb/p/9560403.html   php7安装后没有安装mysqli扩展的话: 安装mysqli扩展 1.到php文件e ...

  8. E1. Array and Segments (Easy version)(暴力) && E2. Array and Segments (Hard version)(线段树维护)

    题目链接: E1:http://codeforces.com/contest/1108/problem/E1 E2:http://codeforces.com/contest/1108/problem ...

  9. linux c中select使用方法

    1.select函数作为定时器使用    it_value.tv_sec = 0;    it_value.tv_usec = 100000:    select(1,NULL,NULL,NULL,& ...

  10. 内核早期内存分配器:memblock

    内核早期内存分配器:memblockLinux内核使用伙伴系统管理内存,那么在伙伴系统工作前,如何管理内存?答案是memblock.memblock在系统启动阶段进行简单的内存管理,记录物理内存的使用 ...