この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。Python公式のzipfileドキュメントを参考に、ZIPを展開せずにファイル名・サイズ・暗号化フラグを確認する方法を整理しました。検証ステータス:📘 公式仕様確認を参考に作成・掲載コードの実機実行は未確認
メールで受け取ったZIPの中身を確認したい。でも、知らないファイルをいきなり展開するのは不安。そんなときは展開せずに目次(中央ディレクトリ)の情報を読む方法があります。Pythonの標準ライブラリ zipfile だけで、ファイル名、元サイズ、圧縮後サイズを一覧表示できます。
| 項目 | 条件 |
|---|---|
| 対象 | ZIPの内容を安全に下調べしたい初心者・業務担当者 |
| 環境 | Python 3、調査対象ZIPのコピー |
| 追加インストール | 不要 |
| ファイル変更 | ZIPを読み取るだけ。展開・上書きしない |
| 制限 | ファイル一覧は確認できるが、中身の安全性や真正性は保証しない |
まず一覧を出してみる
作業用フォルダに調査対象のコピーを sample.zip という名前で置き、次のPythonコードを inspect_zip.py として保存します。機密のファイル名をログや外部サービスへ送らないようにしてください。
from pathlib import Path
from zipfile import ZipFile, BadZipFile
archive = Path("sample.zip")
try:
with ZipFile(archive, "r") as zf:
for item in zf.infolist():
kind = "DIR" if item.is_dir() else "FILE"
encrypted = "yes" if item.flag_bits & 0x1 else "no"
print(
f"{kind}\t{item.file_size}\t"
f"{item.compress_size}\t{encrypted}\t{item.filename}"
)
except (BadZipFile, OSError) as error:
print(f"ZIPを読み取れません: {error}")
先頭から順に、種類、展開後のバイト数、圧縮されたバイト数、暗号化フラグ、ファイル名が表示される想定です。この出力は仕様から導いた期待結果であり、実行ログではありません。
infolist() が返す ZipInfo には、各エントリのメタデータが入っています。file_size は展開後のサイズ、compress_size は圧縮されたサイズです。ディレクトリは is_dir() で判定できます。
観察するポイント
| 観察結果 | 考えられる意味 | 次の対応 |
|---|---|---|
| 想定外のファイル名 | 送信者の説明と内容が違う可能性 | 展開せず送信元へ確認 |
| 展開後サイズが極端に大きい | 展開時にディスク容量を消費する可能性 | 容量と運用制限を確認 |
| 暗号化フラグがyes | 暗号化されたエントリである可能性 | 正規の共有経路で確認 |
| ZIPを読み取れない | 破損・形式違い・アクセス権など | 元データとファイル形式を確認 |
flag_bits & 0x1 はZIPの一般用途フラグの暗号化ビットを確認するだけです。暗号方式やパスワードの強度を評価するものではありません。 また、一覧取得だけでウイルス検査をしたことにもなりません。
なぜ展開しなくても分かるのか
ZIPにはファイル内容とは別に、エントリの名前やサイズを記録する中央ディレクトリがあります。ZipFile はその情報を読み、infolist() で一覧を返します。今回のコードは extract() や extractall() を呼びません。そのためZIP内のファイルを指定フォルダへ書き出しません。
ただし、ZIPの解析自体が完全に無害だという意味ではありません。信頼できない入力は、更新済みのPythonを使い、可能なら隔離された環境で扱ってください。
1か所変えて試す
一覧が長い場合は、for item in zf.infolist(): の直後に次の条件を追加する方法があります。
if item.is_dir():
continue
これでディレクトリエントリを除いたファイル一覧にできます。変更後の期待動作は仕様からの推定で、実行確認済みではありません。
失敗したときの切り分け
FileNotFoundErrorが表示された場合:ZIPの名前と実行時の作業フォルダを確認します。この例ではOSErrorとして捕捉されます。BadZipFileの場合:ファイルが壊れている、ZIP形式ではないなどの可能性があります。拡張子だけでZIPだと判断しないでください。ファイル名が文字化けする場合:ZIP作成ツールの文字コード指定や互換性が原因の場合があります。元ZIPを編集せず、作成元に確認します。
一覧が空の場合:ZIPにエントリがない可能性があります。中身の存在を推測しないでください。
注意:一覧確認と安全な展開は別問題
ZIPのエントリ名には、相対パスや不審な名前が含まれることがあります。名前を確認しただけで安全に展開できるとは限りません。特に、ファイル名を使って独自に保存先を組み立てる処理はパストラバーサル対策が必要です。展開後の合計サイズが巨大なZIPや、多数のエントリを含むZIPにも注意してください。
今回の方法は展開前の一次確認です。受領元の確認、マルウェア対策、必要に応じた隔離環境での検査を置き換えません。
図解:ZIPの「目次」を読む仕組み
ZIPは、ファイルの圧縮データだけの塊ではありません。各エントリの名前やサイズなどを整理した「中央ディレクトリ」という目次があり、PythonのZipFileはそれを使って一覧を作れます。ファイルを実際に外へ書き出す「展開」と、ZIPに記録された情報を参照する「一覧表示」は異なる操作です。
flowchart LR
A["ZIPアーカイブ"] --> B["圧縮された各ファイル"]
A --> C["中央ディレクトリ(目次)"]
C --> D["ZipInfoで名前・容量・フラグを読む"]
D --> E["一覧を表示"]
E --> F["想定外のファイルを探す"]
B -.->|"一覧表示では展開しない"| E
この図は概念図で、ZIP内部の物理的な格納位置を厳密に示すものではありません。目次にある名前を読めても、そのエントリを正常に取り出せることや、安全に実行できることは保証されません。外部から受領したZIPなら、目次の情報も外部入力として慎重に扱います。
中身が分かっている練習用ZIPを作る
知らないファイルを最初の教材にする必要はありません。架空のCSVと短い説明文だけを入れたZIPを自分で作れば、一覧表示の各列と実際の中身を安心して比べられます。次のコードは練習用ファイルを新規作成する例です。同じ名前が存在するときは上書きせず停止します。執筆時点で実行していないため、以下は実測ではなく想定手順です。
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile
output = Path("training-archive.zip")
if output.exists():
raise FileExistsError("同名ファイルがあるため中断します")
with ZipFile(output, "w", compression=ZIP_DEFLATED) as zf:
zf.writestr("report/summary.csv", "項目,値\nA,1\n")
zf.writestr("readme.txt", "これは架空の教材です")
print("練習用ZIPを作成しました:", output)
前半の一覧コードにこのZIPを指定すると、report/summary.csvとreadme.txtが表示される想定です。ZIP内にフォルダーのエントリが常に独立して存在するとは限らないので、「表示はファイル2件なのに、フォルダーも見える」という見かけ上の違いは必ずしも異常ではありません。また、文字数とバイト数も一致しません。日本語を含むテキストのサイズを比較するときは、UTF-8で何バイトになったかも意識すると理解が進みます。
圧縮しても必ず小さくなるわけではない
繰り返しが多い文章は大きく圧縮されやすい一方、JPEG画像や動画のようにすでに圧縮されたデータは小さくなりにくい場合があります。非常に短い文字列では圧縮のための付加情報によって、圧縮後の方が大きく見えることもあります。だから「圧縮サイズが元サイズより大きい」と表示されても、それだけでファイル破損や攻撃とは判断しません。
では、元サイズに対して圧縮サイズが極端に小さかったらどうでしょうか。大量の同じデータを繰り返すファイルも考えられますが、展開時に大量の容量や処理時間を消費するZIP爆弾のようなリスクにも注意します。ただし圧縮率が高いという一つの数値で悪意を確定することも、低いから安全と判断することもできません。ファイル数、元サイズの合計、形式、受領目的を組み合わせて評価します。
展開前に確認する順番
flowchart TD
A["ZIPの一覧を取得"] --> B{"一覧が読めたか"}
B -->|"いいえ"| C["破損・形式・対応版を確認して保留"]
B -->|"はい"| D{"不審なパス・容量・件数があるか"}
D -->|"はい"| E["展開せず送付元と用途を確認"]
D -->|"いいえ"| F["暗号化・期待したファイル名を確認"]
F --> G{"内容を取り出す必要があるか"}
G -->|"ない"| H["一覧確認のみで終了"]
G -->|"ある"| I["別の安全な検査・展開工程へ"]
この流れでは、一覧が読めたからといって安全と認定していません。たとえば業務でPDFを1件受け取る想定なのに、拡張子が実行形式のファイルが何十件も含まれていれば、展開せず受領元へ確認する判断材料になります。逆に期待したPDFの名前だけが並んでいても、中身の真偽やマルウェア混入まで分かるわけではありません。
ZIP内部の名前に親ディレクトリを示す記号や絶対パスのような表記があっても、一覧表示だけでその場所に書き込むわけではありません。しかし、その名前をそのまま保存先に結び付ける独自の展開処理は危険です。パストラバーサル対策は展開工程で別途必要です。暗号化フラグがあっても安全を意味しません。暗号化の有無と内容の検査可能性は別の話です。
一覧を共有する際にもプライバシーを考える
ファイル本体を展開しなくても、内部のファイル名には顧客名・案件番号・個人情報が含まれることがあります。調査ログやチャットにそのまま貼り付けると、目次だけで情報を漏らすことになりかねません。必要な拡張子や件数だけを示すなど、共有範囲を絞ります。ファイル名が文字化けした場合も、すぐに名前を書き換えて元ZIPを保存し直さず、作成元のツールや文字コードに関する条件を確認します。
仕事で使うなら「一次検査」と「安全な展開」を分ける
毎日受信するバッチファイルを例に考えます。決まったCSVがZIPに入っている想定なら、受領直後にファイル名・件数・元サイズを一覧表示し、予定と大きく異なるものを人の確認へ回す設計ができます。これは「内容が正しい」と確認する検査ではなく、「想定どおりの構造に見えるか」を早い段階で確認する検査です。
中身を本当に処理する段階では、ウイルス対策、送付元の信頼性、実際のデータ検証、保存先の権限など別の安全策が必要です。一覧取得に成功したことと業務データとして利用可能なことを混同しないよう、手順書に判定範囲を明記すると実務で使いやすくなります。「開かずに調べられること」と「開かなければ分からないこと」を区別するのが、この小さな技術の大事な使い道です。
まとめ
ZIPをいきなり展開せず、ZipFile.infolist() で中身の名前と容量を確認できます。元サイズと圧縮サイズを見比べ、想定外のファイルや極端な容量があれば、展開前に立ち止まって確認しましょう。安全性の保証ではなく、判断材料を増やすための小さな手順です。
公式資料
検証メモ(2026年11月5日):公式ドキュメントに基づく構成。掲載コードの実行、実ZIPでの検証、WordPress表示確認は未実施です。
