どうもイトサル(@itosaru)です。

Pythonで2重zip(zipの中のzip)の中にあるファイルを読み込みたいです。
zipは解凍したくないのですが何かいい方法はないでしょうか?
私も仕事上で同じことをしようとしたことがあります。
しかし私が調べた限り2重zipの場合は解凍せずにファイルを読み込むことはできないです。
なので仕方なく一度解凍して処理が終わったら削除するというプログラムを書きました。
今回はそのプログラムの書き方などについて説明していきます。
zipの中のファイルなら読み込むことができる
この記事をご覧になっている方はすでにご存知かと思いますが、zipの中のファイルはPython標準モジュールのzipfileをインポートしてreadメソッドを使えば読み込むことが可能です。
なので
- zipfileモジュールで最初のzipを読み込み
- 読み込んだzipをopenメソッドでさらに展開
- 2のzipの中のファイルをread、もしくはopenで読み込めるんじゃ?
と考えたのですが、これをやろうとしたら下のようなエラーが表示され、ファイルを読み込むことができませんでした。
‘<‘ not supported between instances of ‘str’ and ‘int’ xml
エラーを見た限りだと変数のキャストに問題があるような感じですが、変数キャストを色々とためてしてもうまくいきませんでした。調べてみても詳しいことはわからず・・・
なので一時的に外側のzipファイルを展開し、処理が終わったら削除するようにすることでファイルを読み込むようにしました。
サンプルプログラム
次のような2重zipを用意し、その中にtextファイルを入れました。

test.txtには「zipの中のzipにあるテキストファイルです」と記述しておきました。
このzipをドラッグ&ドラッグして中のtest.txtの中身を読み取るサンプルはこちらです。
import xml.etree.ElementTree as ET
import zipfile
import shutil
import re
import os
with zipfile.ZipFile(input("zipファイルをドラッグ&ドロップしてください: ")) as zip:
#インプットzipファイル名格納変数
input_file_name = zip.filename
#インプットファイルのディレクトリ格納変数
input_dir = os.path.dirname(os.path.abspath(__file__)).replace(chr(92),"/") + "/"
#zipの中身のファイル名を取得
file_list = zip.namelist()
#zip内のzipファイルを抽出する
for file in file_list:
match = re.search("\.zip", file)
if match:
zip_file_name = str(file)
zip_dir = zip_file_name.split("/")[0]
zip.extract(file, input_dir)
break
else:
continue
#zip内のファイルを抽出する
with zipfile.ZipFile(input_dir + zip_file_name) as zip_in_zip:
#zip内のファイル名取得
file_list = zip_in_zip.namelist()
#textファイルを取得する
for file in file_list:
text = re.search("\.txt$", file)
if text:
with zip_in_zip.open(file, "r") as readFile:
line = readFile.readline().decode("utf8")
print(line)
break
else:
continue
#解凍したzipファイルを削除する
shutil.rmtree(input_dir+zip_dir)
input()
プログラムの解説をします。
- zipfileでzip.zipを展開する
- 正規表現で「.zip」のファイルを探す
- 見つけたら該当zipをzip.zipと同じディレクトリに展開する
- 3で展開したzip_in_zipをzipfileで展開する
- 展開したzip_in_zipの中を正規表現「.txt」のファイルを探す
- 見つけたら該当ファイルをopenして中身を読み取る
- 読み取り処理完了後、3のzip_in_zipを削除する
ポイントはinput_dirで取得できるディレクトリ階層は「¥」で区切られているため、¥のchr(92)をスラッシュで置き換えて保持しておくこと。
そしてテキストはそのままopenしただけではバイト情報として表示されるためreadlineで文字コードをutf-8で読み取るようにしたことです。
プログラムの実行結果はこちら!

問題なくテキストの中身が読み取れてますね!
合わせて一時的に展開したzip_in_zip.zipが処理後に削除されていることも確認できています。
まとめ
今回は2重zipの中にあるファイルを読み取るプログラムについて説明しました。
改めて今回の内容のおさらいです。
- 2重zipになっているファイルはそのままだと読み込めなさそう
→逆に言えばzipの中のファイルは読み込める - zipの中のzipがなくなるまでzipファイルを展開すれば中身が読み込める
→作業用として一時的に展開し、処理終了後に一括で削除する
使う機会はあまりないかもしれませんが、知っておくと便利です。
Pythonの勉強におすすめな本
Pythonについて勉強したい!という方は
Python 1年生 体験してわかる!会話でまなべる!プログラミングのしくみ
の本がおすすめです。
前ページがカラー印刷で、かわいらしいどうぶつ2人の会話形式で読みやすいです。
内容はPythonの特徴からはじまり、プログラミングの方法、そして簡単な人工知能を作るまでを解説してくれます。
またこの本の続編である、「Python2年生」も発売されているので合わせてどうぞ!
- Python2年生 データ分析のしくみ 体験してわかる!会話でまなべる!
- Python2年生 スクレイピングのしくみ 体験してわかる!会話でまなべる!
コメント