LoginSignup
6
2

More than 5 years have passed since last update.

python3のzipfileで相対パスを指定する時の注意

Posted at

複数のファイルをzipに圧縮するためのpythonスクリプトを作った際に相対パスを使った時のメモです。

結論として「相対パス"../"は使っちゃダメだよ」というお話です。

環境

python 3.6.1
Windows 10

zipfileを使ったサンプルプログラム

例えば「あるディレクトリ配下のファイルを全てzipにする」プログラムは、こんな感じでしょうか。

# -*- coding:utf-8 -*-
import os
import zipfile

TARGETPATH='ここにzipしたいファイルのパス'
with zipfile.ZipFile('test.zip','w',compression=zipfile.ZIP_STORED) as new_zip:
    for f in os.listdir(TARGETPATH):
        new_zip.write(os.path.join(TARGETPATH,f))

注意点はnew_zip.writeの部分。writeメソッドは第1引数(filename)に圧縮対象のファイルパスを渡しますが、第2引数(arcname)が無い場合は第1引数のパス構成がzipファイルに引き継がれます。

圧縮対象パスごとの違い

前述の第2引数(arcname)を指定しない場合に、サンプルプログラムのTARGETPATHに設定したパスによるzipファイルの違いを示します。

絶対パスの場合

# -*- coding:utf-8 -*-
import os
import zipfile

TARGETPATH='C:/test/dir' #絶対パス
with zipfile.ZipFile('test.zip','w',compression=zipfile.ZIP_STORED) as new_zip:
    for f in os.listdir(TARGETPATH):
        new_zip.write(os.path.join(TARGETPATH,f))

完成した圧縮ファイルは絶対パスの構成がそのまま引き継がれます。

test.zip
 └─test
    └─dir
       ├─a.png
       ├─b.png
       └─c.png

相対パス「./」の場合

# -*- coding:utf-8 -*-
import os
import zipfile

TARGETPATH='./dir' #同じ階層のディレクトリを指定する
with zipfile.ZipFile('test.zip','w',compression=zipfile.ZIP_STORED) as new_zip:
    for f in os.listdir(TARGETPATH):
        new_zip.write(os.path.join(TARGETPATH,f))

これもおおよそイメージ通りで./以降のパス構成が引き継がれます。

test.zip
 └─dir
    ├─a.png
    ├─b.png
    └─c.png

相対パス「../」の場合

これが上手くいかないパターンです。

# -*- coding:utf-8 -*-
import os
import zipfile

TARGETPATH='../dir' #一つ上のディレクトリを指定
with zipfile.ZipFile('test.zip','w',compression=zipfile.ZIP_STORED) as new_zip:
    for f in os.listdir(TARGETPATH):
        new_zip.write(os.path.join(TARGETPATH,f))

完成したzipファイルの中身が空になってしまいました。展開することもできません。

test.zip
 └─(empty)



ということで相対パスで上位のディレクトリからファイルを持ってきて圧縮したい場合はzipfile.writeの第2引数(filename)を必ず指定しましょう。

例えば第2引数にファイル名だけ渡すとディレクトリ無しでzipファイルが作られます。

# -*- coding:utf-8 -*-
import os
import zipfile

TARGETPATH='../dir' #一つ上のディレクトリを指定
with zipfile.ZipFile('test.zip','w',compression=zipfile.ZIP_STORED) as new_zip:
    for f in os.listdir(TARGETPATH):
        new_zip.write(os.path.join(TARGETPATH,f),f) #単純にファイル名だけ指定する
test.zip
 ├─a.png
 ├─b.png
 └─c.png

一番良いのは相対パスを使わないことかなと思います。ディレクトリ丸ごとの圧縮ならshutilモジュールを使うのも良いですね。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2