この連載は、『PythonでMarkdownからEPUBをつくろう』を一部抜粋して編集したものです。
本編には、全てのソースコードや、生成する原稿のサンプルが付属しています。ぜひ、こちらもご購入ください。
姉妹版の『PythonとPygameで作る レトロ風RPG 全コード』もあります。
≫ 目次に戻る mod/pack/zip.py
では、作成した02_epub/epub
ディレクトリーの中身を、ZIP形式で圧縮して02_epub/py-md-epub.epub
ファイルを作ります。
圧縮は、Python標準ライブラリーのzipfile
を使います。先頭に無圧縮でmimetype
を格納して、以降は全てのファイルを圧縮しながら追加していきます。
それではファイル構成とプログラムを示します。
gen-epub/
main.py
config.yaml
mod/
pack/
zip.py
1import os, zipfile
2from pathlib import Path
3from mod.util import file as uf
4
5# ZIPで固めてEPUBを出力
6def gen(data):
7 dir = data['dirs']
8 con = data['config']
9
10 # すでにあればゴミ箱に
11 uf.exist2trash(con['pEpub'])
12
13 # ZIPで圧縮してEPUBを作る
14 with zipfile.ZipFile(con['pEpub'], 'w',
15 compression = zipfile.ZIP_DEFLATED,
16 compresslevel = 9) as zf:
17 append_mimetype(zf, dir) # mimetypeの格納
18 append_rest(zf, dir) # 残りのファイルの格納
19
20# mimetypeの格納(先頭に無圧縮で追加する必要がある)
21def append_mimetype(zf, dir):
22 p = uf.join(dir['outputEpub'], 'mimetype')
23 zf.write(p, 'mimetype', compress_type=zipfile.ZIP_STORED)
24
25# 残りのファイルの格納
26def append_rest(zf, dir):
27 for d_this, _dirs, files in os.walk(dir['outputEpub']):
28 # 相対パスを用意
29 d_rel = str(Path(d_this).relative_to(dir['outputEpub']))
30 #print(d_this, _dirs, files, d_rel)
31
32 # ルートでないならディレクトリーを作る
33 if d_this != dir['outputEpub']:
34 zf.mkdir(d_rel)
35
36 # ファイルの処理
37 for name in files:
38 # 格納済は飛ばす
39 if name == 'mimetype': continue
40
41 # ファイルを格納
42 p = os.path.join(d_this, name)
43 arcname = os.path.join(d_rel, name)
44 zf.write(p, arcname)
45 print(f'- {arcname}')
少し長いので分割して説明します。
まずはインポート部分です。
1import os, zipfile
2from pathlib import Path
3from mod.util import file as uf
ファイルのZIP圧縮にはPython標準ライブラリーのzipfile
を利用します。
相対パスを求める必要があるので、Python標準ライブラリーのpathlib
のPath
を読み込みます。
続いて、ZIPでファイルを固めてEPUBを出力する処理です。詳細部分は別の関数でおこないます。
5# ZIPで固めてEPUBを出力
6def gen(data):
7 dir = data['dirs']
8 con = data['config']
9
10 # すでにあればゴミ箱に
11 uf.exist2trash(con['pEpub'])
12
13 # ZIPで圧縮してEPUBを作る
14 with zipfile.ZipFile(con['pEpub'], 'w',
15 compression = zipfile.ZIP_DEFLATED,
16 compresslevel = 9) as zf:
17 append_mimetype(zf, dir) # mimetypeの格納
18 append_rest(zf, dir) # 残りのファイルの格納
まず、EPUBファイルがすでにある場合はゴミ箱に送ります。
次にwith
文でZIPファイルを開きます。このときの設定は、パスはcon['pEpub']
、モードは書き込みモードでw
、圧縮方式compression
はzipfile.ZIP_DEFLATED
(通常のZIP圧縮)、圧縮レベルcompresslevel
は最大の9
です。
con['pEpub']
。config.yaml
のpEpub
に書いたパス。w
。compression
の設定。zipfile.ZIP_DEFLATED
(通常のZIP圧縮)。compresslevel
の設定。9
。 この設定で開いたZIPファイルを変数zf
で操作可能にします。
続いて2つの処理をおこないます。「mimetypeの格納」と「残りのファイルの格納」です。このあとは、この2つの処理を見ていきます。
mimetype
ファイルを、ZIPファイルの先頭に無圧縮で追加します。
20# mimetypeの格納(先頭に無圧縮で追加する必要がある)
21def append_mimetype(zf, dir):
22 p = uf.join(dir['outputEpub'], 'mimetype')
23 zf.write(p, 'mimetype', compress_type=zipfile.ZIP_STORED)
ZIPファイルへのファイルの追加はzf.write()
関数でおこなえます。関数の引数は、第1引数が追加するファイルのパス、第2引数がZIPファイル内のパスです。
第1引数は、ローカルファイルの絶対パス~02_epub/epub/mimetype
を指定しています。第2引数は、ファイル名のmimetype
を指定しています。
続いて引数にcompress_type=zipfile.ZIP_STORED
と指定します。この設定を加えると、無圧縮でファイルを追加します。
mimetype
以外のファイルを、ZIPファイルに追加します。ここではcompress_type
の指定をおこないません。そのため、ファイルを開いたときの圧縮設定でファイルは追加されます。
25# 残りのファイルの格納
26def append_rest(zf, dir):
27 for d_this, _dirs, files in os.walk(dir['outputEpub']):
28 # 相対パスを用意
29 d_rel = str(Path(d_this).relative_to(dir['outputEpub']))
30 #print(d_this, _dirs, files, d_rel)
31
32 # ルートでないならディレクトリーを作る
33 if d_this != dir['outputEpub']:
34 zf.mkdir(d_rel)
35
36 # ファイルの処理
37 for name in files:
38 # 格納済は飛ばす
39 if name == 'mimetype': continue
40
41 # ファイルを格納
42 p = os.path.join(d_this, name)
43 arcname = os.path.join(d_rel, name)
44 zf.write(p, arcname)
45 print(f'- {arcname}')
ディレクトリ内のパスはos.walk()
関数で次々に得ます。
for d_this, dirs, files in os.walk(ディレクトリAのパス):
のように書くと、ディレクトリA内を次々と走査していきます。
そして、d_this
(現在のディレクトリ)、dirs
(現在のディレクトリ内にあるディレクトリのリスト)、files
(現在のディレクトリ内にあるファイルのリスト)を得られます。
d_this
dirs
files
Path(パス).relative_to(ルートのパス)
関数で相対パスを得ます。この戻り値はテキストではないので、str()
関数でテキストに変換します。
次に、現在のディレクトリが、ルートのディレクトリでないならZIPファイル内にディレクトリを作ります。ディレクトリの作成は、zf.mkdir(ディレクトリのパス)
でおこないます。
そしてリストfiles
を使い、ファイルを1つずつ追加していきます。ファイルの格納は、zf.write(パス, 格納の相対パス)
でおこないます。このとき、mimetype
は追加しないようにします。
この連載は、『PythonでMarkdownからEPUBをつくろう』を一部抜粋して編集したものです。
本編には、全てのソースコードや、生成する原稿のサンプルが付属しています。ぜひ、こちらもご購入ください。
姉妹版の『PythonとPygameで作る レトロ風RPG 全コード』もあります。