Python

pythonで自動的に特定フォルダの中身を移動するコード

更新日:

かなり特殊なケースですが、あるフォルダに入ってくるファイルを自動的に希望のフォルダに移したいとします。DocuWorksのようなフォルダを監視するアプリで、特定のフォルダにファイルが入ったことを通知するような場合ですね。自分専用のフォルダをいくつも作ってしまうと、その分監視トレイも増やさなければならず、デスクトップがトレイで埋め尽くされます。

そこで、複数ある自分用フォルダに入ったファイルを自動的に特定のフォルダに移し、その特定フォルダだけをDocuWorks等で監視するようにすれば、デスクトップもスッキリするばずです。

フォルダにあるファイルを定期的に違うフォルダに移動するスクリプトを、私のつたないPythonで書いてみました。

ファイルを自動移動するPythonスクリプト

以下のスクリプトは下記の環境で確認しています。

  • OS:Windows10 pro 64bit
  • Ptyhon: 3.7.1
  • NAS:QNAP TS-469

60秒に1回、移動元のフォルダを見に行き、ファイル(フォルダ含む)があれば移動先フォルダに移動するコードです。移動時にエラーがあれば、その内容をcsvファイルに記録します。基本的なエラーは無視して、ファイルの移動を止め、また60秒後にファイルの移動を実行する内容です。

このスクリプトが動いている間はずっと移動元のフォルダを監視し続けます。

import shutil
import os
import time
import sys
from datetime import datetime

src_dir = '移動元PATH'
dst_dir = '移動先PATH'

def time_conv():
  dt = datetime.now()
  return dt.strftime('%Y-%m-%d %H:%M:%S')


def save_log(e):
  log_data = time_conv() + str(e.args)
  with open('errorlog.csv', 'a') as f:
    print(log_data, file=f)


def move_files(src_dir, dst_dire):
  while True:
  try:
   if os.path.isdir(src_dir) and os.path.isdir(dst_dir) == True:
       filename = os.listdir(src_dir) #移動元フォルダの中のファイルをすべて取得
       for p in filename:
         shutil.move(os.path.join(src_dir, p), dst_dir)

      else:
        raise FileNotFoundError('指定フォルダーが見つかりません')

    except FileNotFoundError as e:
      save_log(e)
      sys.exit() #スクリプト自体を停止する

    except Exception as e:
      save_log(e)
      pass

    time.sleep(60)

if __name__ == '__main__':
  print('running...')
  move_files(src_dir, dst_dir)

このコードでは、Pythonの持つ標準のライブラリを使って実装しているため、おそらく3.5などの古いバージョンのPythonでも動くんじゃないかと思います。(未確認ですが)

このコードを使用するにあたり、いくつか注意点がありますので解説を交えながら記していきます。

Pythonでフォルダの有無を確認する

Pythonでフォルダの有無を確認するには「osライブラリ」を使用します。whileループ分の中に


if os.path.isdir(src_dir) and os.path.isdir(dst_dir) == True:

という記述が出てきますが、ここでは移動元フォルダと移動先フォルダが存在するかどうか確認しています。どちらも存在する(True)の場合のみファイルの移動が実行されるようにしています。

こういうロジックにしておかないと、恐ろしいことが起こりかねます。

たとえば、移動元フォルダだけ正しくPathが指定されていて、移動先フォルダのPathが間違っていたとします。両方のフォルダ指定が正しいことを確認せずファイルの移動を実行した場合、移動元フォルダからファイルを消したものの、移動先が見つからずスクリプトが終了します。

つまり、ファイルのボリュームが消えます。

ファイル自体は消えないのですが、ボリュームが消えるので、ファイルが持っていたPathが消えます。私はスクリプトを試していた時にこのミスをやらかしまして、冷や汗をかきました。移動元であったNASを再起動したところ何事もなく復帰しましたが、自動ってのは恐ろしいものですね。ということで、フォルダの存在確認は必須です!!

もし、移動元/移動先どちらかのPathが存在しなかった場合は、条件分岐でelseに飛ばし、raiseでエラーをFileNotFoundErrorを強制的に出します。エラーを受け取った場合は、エラーログを吐き出すようにしています。

if文で移動元/移動先のPath確認がfalseとなってもエラーではないため、強制的にエラーを出すためにraiseを設定しています。こうすることで、Pathが存在しなかった時にログを残し且つ、スクリプトを止めるということができます。

ちなみに、その他のエラーの場合は、エラーログを残しつつ、エラーを無視してスクリプトは実行し続けるように組んでいます。この辺りは、使用状況によりけり、例外処理を組めばよいでしょう。

たとえば、「移動先に同じ名前のファイルがあれば、リネームして移動する」といったこともできます。try-exceptでどんな例外を出せるかはPythonのDocumentに書いてあります

Pythonでのファイル移動は「shutilライブラリ」を使う

shutilはPythonの標準ライブラリです。ファイルに関するあらゆる操作ができる万能ライブラリです。shutilを使ったファイル操作の方法は、下記の記事を参考にしました。

今回はshutilから「move関数」を使います。

for p in filename:
  shutil.move(os.path.join(src_dir, p), dst_dir)

とすることで、移動元フォルダの中身をひとつずつ取り出して、移動先のフォルダに移動します。

スクリプトを自動化する際はエラーログの取得は必須

こういった自動化プログラムは、バックグランドで動くため、エラーログの取得は必須と考えています。特に、NASのようなファイルサーバ上のファイルを自動で移動するようなスクリプトでは、エラーが起こった時に一体何が起こったのか知る必要があります。

そこで今回のスクリプトでは、起こったエラーの内容をcsvファイルに書き出す関数(save_log)を用意し、エラーの内容をcsvファイルに追記していく仕組みとしました。

エラーログの取得が必要ないケースでは、こういった関数を用意する必要はありません。

今回のスクリプトではエラーログに発生年月日を付けてcsvに追記していく仕様としました。Pythonで日付を扱うにはdatetimeという標準ライブラリを用いますが、datetimeで返ってくる値はタプル型となり、そのままでは文字列として扱えません。

そこで、タプル型で返ってくる日付を文字列に変換する関数(time_conv)を用意し、エラーログに日付を付けてCSVに書き出す仕様としています。

NAS(Linux)にpythonスクリプトを仕込むにはnohupが便利

上記スクリプトは、Pythonが入っている環境(WindowsでもLinuxでも)使用できます。しかし、NASのようなネットワークドライブにリモートでログインしてPythonスクリプトを実行するとなると、ログインが切れた瞬間にPythonスクリプトも終了指定しまします。

そこで、リモートログインが切れた後でも動き続けるように、Linuxでは「nohup」というコマンドでpythonスクリプトを実行します。このコマンドを付けることで、NAS自体が落ちた時や、スクリプトの動作で終了に至った場合以外では動き続けるようです。

詳しくは下記記事で詳しく解説されています。

今回作成したPythonスクリプトのファイル名がtest.pyだったとして、

>nohup python test.py > /dev/null 2>&1 &

で実行します。これでログイン後もスクリプトが動き続けます。ちなみにnohupコマンドは、自動でログを出力してくれる機能がありますが、エラー以外のログもどんどんたまっていくので、「/dev/null 2>&1 &」とすることで、ログ出力を自動破棄しています。エラーログは別途csvに取得していますからね。

nohupの止め方

>ps u

としてpythonスクリプトの実行PIDを確認

>kill -KILL PID

でスクリプトの停止

NASが落ちた場合はPythonスクリプトも止まっているので、再度「nohup python~」でスクリプトを動かしてあげる必要あり。NASを夜中に定期的に再起動するような設定の場合は「cron」コマンドでPythonスクリプトが自動起動するような設定が有効でしょう。

さいごに

Pythonの豊富なライブラリを使えば、「市販のアプリの”ちょっと足りない”ところ」を自分で補えます。

Pythonの書き方の情報はネット上にあふれているので、私のようにPython初級者でも思ったような処理を書くことができます。もう少し読みやすく簡潔に書く方法があると思いますが、まずは動くものを書いて、実際に業務で使えるということが大切です。

「こんなことが自動化出来たら楽なのに」という思いが鎮火してしまう前にコードを走らせることが大切ですね。

あなたにおすすめの記事
➡「「現役シリコンバレーエンジニアが教えるPython入門」【やってみた】

タグ

カテゴリー

  • この記事を書いた人
アバター

from-age35

中小企業エンジニアです。35歳で急遽プログラミングを覚えることになり、PythonやJavaScriptなどをゆっくりマイペースに覚えています。先端スキルには疎いですが、楽しくコーディングしてます♪最近の興味は【WEB開発】です

-Python

Copyright© 35からのプログラミング , 2019 All Rights Reserved Powered by AFFINGER5.