Java对epub电子书类型切割

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解压看下。如下图

5c0f4fbdb1783.png

可以很清楚看见是由xhtml文件组成资源。关于content.opf ,toc.nxc等这些本来就是属于电子书的数据结构文件,可以自行网上查阅。

epublib中book数据结构

epub电子书抽象成epublib中的book 。epublib 中book的数据结构是怎么样子的呢,这里稍微介绍一下,网上确实资料太少了。

5c0f4fd52c53a.png

Resource数据结构

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

5c0f4fe6360bb.png

  1. id,href相当于Resources中那个HashMap中的key,可以找到Resource
  2. title 和 originalHref 表资源的名字和起始的href
  3. mediaType 资源的数据类型 inputEncoding 编码格式
  4. data 第一张图片上的.xhtml转string类型,然后再转成字节流的数据

Metadata

Book里的Metadata相当于电子书的头部,可以获取电子书的基本数据,数据结构如下:

5c0f500842a69.png

Spine

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

5c0f4ff770c86.png

Resource 与ResourceReference 为关联,SpineReference是ResourceReference的父类。

在设置好Resouces后一定要设置相应的Spine中的Resouce,不然电子书打开,会无法识别。

TableOfContents

Book中目录对应的数据结构。有目录的名字,目录对应的Resource,对应的数据结构如下:

5c0f50404759a.png

实战

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;
    }

转载于:https://www.cnblogs.com/Krloypower/p/9732476.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值