🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

925閲覧

Python: フォルダに入ったZipを自動解凍したい(続き)

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2019/12/21 05:58

こちらの質問の続きです.
watchdogというフォルダ監視ができるライブラリを使用しています.

現在のコード

Python

1from watchdog.events import FileSystemEventHandler 2from watchdog.observers import Observer 3import os 4import time 5import zipfile 6import rarfile 7 8os.chdir(os.path.dirname(os.path.abspath(__file__))) 9rarfile.UNRAR_TOOL = os.getcwd()+r'\UnRAR.exe' 10 11if not os.path.exists("settings.ini"): 12 tmp=input("絶対パスで監視したいフォルダを指定してください(フォルダをDDすると楽)\n>>>") 13 if not os.path.exists(tmp): 14 print("そのディレクトリは存在していません") 15 exit() 16 17 with open("settings.ini",'w') as f: 18 f.write(tmp) 19 20with open("settings.ini",'r') as f: 21 target_dir = f.read() 22 23print('監視フォルダ:'+target_dir) 24 25class ChangeHandler(FileSystemEventHandler): 26 def on_created(self, event): 27 pass 28 29 def on_modified(self, event): 30 filepath = event.src_path 31 filename = os.path.basename(filepath) 32 33 if filepath[-4:]=='.zip' : 34 with zipfile.ZipFile(filepath) as zf: 35 zf.extractall(target_dir) 36 print('%sを解凍しました'% filename) 37 elif filepath[-4:]=='.rar' : 38 with rarfile.RarFile(filepath) as rf: 39 rf.extractall(target_dir) 40 print('%sを解凍しました'% filename) 41 else: 42 pass 43 44 def on_deleted(self, event): 45 filepath = event.src_path 46 filename = os.path.basename(filepath) 47 print('%sを削除しました' % filename) 48 49if __name__ in '__main__': 50 while 1: 51 event_handler = ChangeHandler() 52 observer = Observer() 53 observer.schedule(event_handler, target_dir, recursive=True) 54 observer.start() 55 try: 56 while True: 57 time.sleep(0.1) 58 except KeyboardInterrupt: 59 observer.stop() 60 observer.join()

注:前回の質問ではzipfile.is_zipfile(filepath):で判定をしてましたがこの場合だとzipファイル以外にも反応することがわかり,拡張子判定に切り替えています.

こちらを実行してzipファイルを投げますと,

Python

1line 34: with zipfile.ZipFile(filepath) as zf: 2PermissionError: [Errno 13] Permission denied: (filepath

のようにエラーが出ます.

PermissionErrorが出るということは, 複数のプロセスが何かしら同じファイルを対象にしていると考えてられるので, def on_modified(self, event):の挙動を調べようと思いました. else文をpassからprint("a")にして挙動を調べますと, 130kbの一つのファイルを投げ込んだだけでaが4回出力されたため, この関数は(ファイルのサイズにもよりますが)複数回起動しているみたいです.

つまり, 最初の

with zipfile.ZipFile(filepath) as zf:    zf.extractall(target_dir)

の処理中にまたwith zipfile.ZipFile(filepath) as zf: が複数回起動しているため参照の重複が発生してエラーが出ていることがわかります.

つまり, ぱっと思いつく解決案としてはwith zipfile.ZipFile(filepath) as zf:が一回だけ作動するようにできればエラーは発生しなさそうですが, 何か妙案はないでしょうか...

※ちなみにdef on_created(self, event):はファイルが入った瞬間に起動するだけで,フォルダにファイルがコピー完了する前に反応してしまうため, こちらに解凍のコードを書いても実行することができません.

よろしくお願いします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Python

1def on_modified(self, event): 2 try: 3 filepath = event.src_path 4 filename = os.path.basename(filepath) 5 time1=os.path.getsize(filepath) 6 time.sleep(0.001) 7 time2=os.path.getsize(filepath) 8 if time2-time1 == 0: 9 if filepath[-4:]=='.zip' : 10 with zipfile.ZipFile(filepath) as zf: 11 zf.extractall(target_dir) 12 print('%sを解凍しました'% filename) 13 os.remove(filepath) 14 elif filepath[-4:]=='.rar' : 15 with rarfile.RarFile(filepath) as rf: 16 rf.extractall(target_dir) 17 print('%sを解凍しました'% filename) 18 os.remove(filepath) 19 else: 20 pass 21 else: 22 pass 23 except Exception as e: 24 pass

こんな感じで実装しました 一回だけ動作させるようにするのではなく, サイズの差分で分岐を作り, 複数回の判定の内一回だけ動作させるようにしました.

質問している分際で偉そうなことを書きたくないですが, 最近はまともな回答が返ってこないことが多くてつらいですね.

投稿2019/12/24 03:11

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

なにかフラグ用意しといて、そいつがfalseのときにだけ作動させれば。
もちろん作動中はtrueにしておく

投稿2019/12/21 06:04

y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問