複数のファイルを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
モジュールを使うのも良いですね。