壁打ちAtCoder

AtCoderの問題をひたすら解いてくブログです。思考やコードの書き方の私的備忘録として

Pythonでzip圧縮を行うコード

パスワードなしzip圧縮

ただのzip圧縮の場合。
zipfileという標準モジュールを利用する。

docs.python.org

import os
import zipfile

file_name = "sea"  # ファイル名(拡張子なし)
dir_path = "C:/Users/user_name/Desktop"  # ファイルのあるディレクトリのパス
src = os.path.join(dir_path, file_name + ".png")  # 圧縮するファイルのパス(file_name+拡張子)
zip_path = os.path.join(dir_path, file_name + ".zip")  # 圧縮後のファイルのパス

with zipfile.ZipFile(zip_path, "w") as zf:
    zf.write(src, arcname=os.path.basename(src))
# 第一引数のファイルを、第二引数の名前でzipファイルに書き込む(省略可)

パスワードなしzipファイル解凍

zipfileを用いて解凍もできる。

import os
import zipfile

zip_path = "C:/Users/user_name/Desktop/sea.zip"  # 解凍するzipファイルのパス
dir_path = os.path.dirname(zip_path)  # 解凍先のパス

with zipfile.ZipFile(zip_path, "r") as zf:
    zf.extractall(path=dir_path)

パスワード付きzip圧縮

zipfileではパスワードを付けられないので、pyminizipというモジュールを使う。
pipでインストールする必要あり。

pip install pyminizip

Visual C++がないとinstallで失敗するらしいので、その旨のエラーが出たら、まずはC++をインストールする。

Desktopにあるsea.pngというファイルを圧縮してsea.zipにするコード

import os
import pyminizip

file_name = "sea"  # ファイル名(拡張子なし)
dir_path = "C:/Users/user_name/Desktop"  # ファイルのあるディレクトリのパス
src = os.path.join(dir_path, file_name + ".png")  # 圧縮するファイルのパス(file_name+拡張子)
zip_path = os.path.join(dir_path, file_name + ".zip")  # 圧縮後のファイルのパス
pyminizip.compress(src.encode("cp932"), "", zip_path.encode("cp932"), "password", 5)

ファイル名に日本語が含まれる場合は.encode("cp932")が必要らしい(参考記事②より)。
これはWindowsがcp932を使っているためらしいので、Windows以外なら不要なのかもしれない(試してないのでわからないけど)
上述のコードでzip圧縮した場合、解凍する時にファイル名が文字化けしてしまうので、少し工夫してやる必要がある。

パスワード付きzipファイル解凍

圧縮と異なり、解凍の方はzipfileでできる。(圧縮もできて欲しいんですけど……

import os
import zipfile

zip_path = "C:/Users/user_name/Desktop/sea.zip"  # 解凍するzipファイルのパス
dir_path = os.path.dirname(zip_path)  # 解凍先のパス
with zipfile.ZipFile(zip_path, "r") as zp:
    zp.extractall(path=dir_path, pwd="password".encode("utf-8"))

zip圧縮時にencode("cp932")を用いた場合はファイル名のエンコードデコードをいじってやる必要がある(参考記事③より)。

import os 
import zipfile

zip_path = "C:/Users/user_name/Desktop/海.zip"  # 解凍するzipファイルのパス
dir_path = os.path.dirname(zip_path)  # 解凍先のパス

with zipfile.ZipFile(zip_path, "r") as zp:
    for info in zp.infolist():
        info.filename = info.orig_filename.encode("cp437").decode("cp932")
        if os.sep != "/" and os.sep in info.filename:
            info.filename = info.filename.replace(os.sep, "/")
        zp.extract(member=info, path=dir_path, pwd="password".encode("utf-8"))