【Python】フォルダの中にあるファイル名を判断して同じものを移動させるプログラム
このプログラムは条件をもとにデータを移動させるプログラムです。移動するデータの名称と移動先にあるデータの名称を比較して、一致するものだけを移動する仕様になっています。毎号続く雑誌や何巻も続く本などの電子書籍、資料やデータ類を特定の場所に移動させるのに向いています。
※このプログラムはプログラム言語『Python』のインストール、および各モジュールが使用可能な状態であることが前提となります。
当サイトではアフィリエイト広告を利用しています。
リンクや画像に広告が含まれている場合があることを予めご了承ください。
同じタイトルを仕分けるプログラム
移動元フォルダにあるファイルの名称を移動先にあるファイルの名称と照合して、それぞれ該当する場所に移動します。仕分け対象は『 第』(半角スペース+第)という文字が入っているファイルとなります。この文字を基点としてタイトル名を抜き出し照合させます。
例えば『sampleA 第10号』というファイルがあった場合、『sampleA』だけ抜き出して移動先のファイル名(こちらもタイトル名だけ抽出)と比較します。一致したらそこへ移動させます。
移動先に対象ファイルがない場合は移動しません。
ちなみに仕分け対象文字は変更も可能です。『アンダースコア(_)』や『No.』『Vol.』といった文字でも可能です。ファイル名の付け方に沿って変更してもらえればいいと思います。
プログラムの使い方
下記のコードをpyファイルにコピペする
import os
import glob
import shutil
def file_move(move_path):
for x in glob.iglob('C:\\移動元パス\\**', recursive=True):
for y in glob.iglob(move_path+'**', recursive=True):
if os.path.isfile(x) and x[x.rfind('\\')+1:x.rfind(' 第')] == y[y.rfind('\\')+1:y.rfind(' 第')]:
shutil.move(x, move_path+x[x.rfind('\\')+1:])
print(x, 'を 【', move_path, '】へ移動しました')
file_move('C:\\移動先パス1\\')
file_move('C:\\移動先パス2\\')
input(
'''
Enterキーを押してください
'''
)
移動前フォルダの絶対パスを入力
for x in glob.iglob('C:\\移動元パス\\**', ~
上記に該当する『C:\\移動元パス』を削除して、移動したいデータがあるフォルダの絶対パスを入力してください。間違ってシングルクォーテーション(´)を消さないでください。正しく機能しなくなります。フォルダ間の区切りはバックスラッシュ(\)または半角¥マーク2つです。
移動先フォルダの絶対パスを入力
file_move('C:\\移動先パス1\\')
file_move('C:\\移動先パス2\\')
file_moveの『C:\\移動先パス1』と『C:\\移動先パス2』を削除して、移動先のフォルダの絶対パスをそれぞれ入力してください。
デフォルトでは移動先を2つ入力するようになっていますが、1つでいいなら『file_move('C:\\移動先パス2\\')』を削除してください。逆に増やしたいなら、移動先フォルダの数だけコピペして、パスを入力していってください。
編集内容を保存後、pyファイルをダブルクリック
正常に移動ができた場合は、下記のようなテキストが表示されます。
C:\移動元パス\ファイル名 を 【 C:\移動先パス1\ 】へ移動しました
正常に移動ができていない場合は、指定した場所のパスが間違っているか、プログラムコードの記述が正しく変更できていない、または間違って手を加えてしまったかのどれかになるでしょう。再度確認してみてください。
プログラムの処理が終わったらEnterキーを押して画面を閉じる
このプログラムを実行するとコマンドプロンプト(pyファイル実行時に出てきた黒い画面)が立ち上がります。移動処理が済んだら「Enterキーを押してください」と出るので、そこでEnterキーを押せば画面が閉じて完了、という仕様になっています。
基本的に処理だけ書いたプログラムを実行したら、コマンドプロンプトが立ち上がって処理を始め、完了後は自動で画面が閉じて終了になります。しかし、それだとちゃんと移動したのか、エラーは出なかったかなどを確認できなくなります。結果だけ残って過程がどうなっているかがわからなくなります。
ちゃんと移動したかどうかを確認するためにも、コマンドプロンプトを自動で閉じるのではなく、Enterキーを押して閉じるようにしました。画面上には処理した内容が表示されているはずなので、不備がないか確認してください。問題なければEnterキーを押せば画面が閉じます。
ちなみに、Enterキーをいちいち押すのは面倒だ、という人は下記の部分を削除して下さい。
input(
'''
Enterキーを押してください
'''
)
ここは最後のキーを押す作業を司っている処理です。ここを削除すれば自動で閉じるようになります。
以上で使い方の説明は終了です。
ファイル名を取得→処理、の工程は効率化への第一歩
ファイル名を取得して、それに何かしらの処理を加える、といった作業工程はいろいろな場面で活用します。ことプログラムにおいてはパソコン作業を効率化させる常套手段といっても過言ではありません。
今回は該当するものの文字列を抽出して比較後に移動させていますが、活用次第で便利なプログラムになると思います。画像でもエクセルデータでも何かしらの資料でもまとめる時に楽になります。
1つ1つのデータをどこに保管しているかを探すのも面倒な場合がありますし、フォルダを開いては閉じてを繰り返す手間もかかります。
ちまちました作業こそプログラム化すると格段に効率が上がります。普段のパソコン作業にプログラムを落とし込めれば、どんどん効率が良くなりますよ。
プログラムの各部説明
ここからの説明は、どういった考えの元でプログラムを書いたかを残しておくためのものです。プログラムに興味がない人は読み飛ばしていただいてかまいません。
モジュールの読み込み
モジュールとはプログラムの部品のことです。プログラムを書く場合、頻繁に使用するコードが出てきます。コードが長くなったりすると、それらを使うたびに何度も1から書いていくのは効率が悪いです。そういうよく使うコードをまとめておき、いつでも手軽に利用できるようにしたものがモジュールです。
モジュールを使うにあたっては事前にそれを取り込む(インポート)必要があります。モジュールのインポートは『import モジュール名』と書きます。
今回のプログラムではosモジュール、globモジュール、shutilモジュールを使って構築しています。
import os
import glob
import shutil
これでモジュールを使うことができます。
独自の関数定義:file_move
def file_move(move_path):~printの行までは、独自の関数として共通化しています。今回のプログラムは移動元と移動先を指定してファイルを移動させます。移動先となる場所が複数ある場合でも対処できるようにしています。
移動場所が複数ある場合はその都度、移動処理を行うのですが、その場合にかぶる処理が出てきます。それらを毎度書いていくと無駄に長いコードになってしまいます。処理が同じならそれを共通化させて、必要になったらその都度そこを通していく方が効率的で、また修正も楽になります。そうして作ったのがfile_moveという独自定義関数です。
def file_move(move_path):
file_moveという名称で関数を定義しています。move_pathはこの関数を呼び出す時に指定した『移動先のパス』が入力されます。
for x in glob.iglob('C:\\移動元パス\\**', recursive=True):
for y in glob.iglob(move_path+'**', recursive=True):
指定したパスのサブフォルダ内を含めた全てのファイル名とフォルダ名を取得して、そこから1つずつ取り出し、変数x、yに代入します。
glob.iglob()はカッコ内にパスを指定するとその中にあるファイル名とフォルダ名を取得します。あくまでフォルダの中のみが対象で、その中に別のフォルダがあってもそのフォルダの中も含めて取得するわけではありません。
フォルダの中にあるフォルダの中も取得する場合はrecursive=Trueを指定します。recursiveとワイルドカード(*)によって、指定フォルダのサブフォルダ内を含めた全てのデータを取得することができます。
取得したファイル名群をfor文で1つずつ取り出し、変数xとyにそれぞれ代入します。早い話が、xは移動元のデータ名、yは移動先のデータ名が代入されることになるわけです。
if os.path.isfile(x) and
x[x.rfind('\\')+1:x.rfind(' 第')] ==
y[y.rfind('\\')+1:y.rfind(' 第')]:
※コードは見やすいようあえて改行していますが、本来は1行で書きます
これは2つの条件を与えて、その両方を満たすものだけを処理する、という意味になります。
1つ目の条件は、x(移動元のデータ)がファイルであること。
2つ目の条件は、xとy(移動先のデータ)の一部分を抽出した文字列が同じであること。
今回のプログラムは、タイトルが同じファイルを照合して一致する場所にそれぞれ移動させるプログラムです。フォルダは移動させません。しかし、先ほどglobでファイル名とフォルダ名の両方を取得しています。必要なのはファイルだけなので、1つ目の条件でその仕分けをしているわけです。
2つ目の条件の一部分を抽出した文字列というのは、本や雑誌、データ名のタイトル部分のことです。
【プログラムの説明】の部分でも触れていますが、移動元と移動先にあるファイル同士のタイトルが同じ場合に移動させます。であれば、どちらのファイルもタイトル名だけを抜き取って、それが等しいかどうかを照合すればいいわけです。それを行うのが2つ目の条件というわけです。
スライスとrfindメソッドで抽出
ファイル名を抽出するために、x[x.rfind('\\')+1:x.rfind(' 第')]としています。これはスライスとrfindメソッドを組み合わせた文字列の抽出方法です。
まず、ここでの『x』というのは移動元フォルダの中にあるデータ名になりますが、それは絶対パスで取得しています。例えば『sampleA 第09号.zip』というデータがあった場合、xは次のようになります。
スライスは文字列などを部分的に切り出す機能を持っていて、以下のように指定します。
スライスの指定方法
文字列[開始インデックス:終了インデックス]rfindメソッドは文字列から『指定した文字列を末尾から検索する』機能を持っていて、以下のように指定します。
rfindメソッドの使い方
文字列.rfind(検索文字列)ちなみに、findというメソッドもあって、findは先頭から検索して、rfindは末尾から検索をします。今回は先頭から検索するとパスの区切りでファイル名を正確に抜き出すことが難しいので、末尾から検索して最初にヒットするパスの区切りがファイル名の直前の区切りであることを利用してrfindを指定しています。
+1というのは『インデックスにプラス1する』という意味で、該当した場所の『1文字後から』という解釈になります。そもそもスライスは開始と終了で指定したインデックスを含む・含まないが決まっています。開始の方は指定したインデックス自体を含み、終了の方は指定したインデックス自体を含みません。
今回においては『x.rfind('\\')+1』が開始を意味しています。xの文字列の末尾から『\\』を検索。開始の場合はこの文字自体を含む、つまり『\\』自体を含むことになり、これを含めてしまうとパスがおかしくなるので、含めないようにその1文字後から抽出を開始します。
終了はx.rfind(' 第')になりますが、ファイル名が『タイトル 第○○号(巻)』という命名になっているので、タイトルを抜き出す時には『 第』という文字列がちょうどよい目安になります。終了インデックスは指定したインデックス自体を含まないので、『 第』の前までが対象となります。
このように開始と終了の範囲を上手く指定することによって、絶対パスの中からタイトル名だけを抜き取ることができます。
仮にファイル名が『sampleA Vol.09.zip』だったなら、rfindメソッドで指定する文字列を『 Vol』に変えればいいだけです。同様に『sampleA No.09.zip』なら『 No』というように応用が利きます。ファイル名をどう命名しているか、その付け方に沿って変更してもらえればいいと思います。
shutil.move(x, move_path+x[x.rfind('\\')+1:])
move('移動前の場所+ファイル(ディレクトリ)名', '移動先の場所+ファイル(ディレクトリ)名')を表しています。移動には移動元と移動先の正確な場所ならびに何を移動させるのかそのファイル名が必要です。
C:\\移動元\\ファイル名
↓
C:\\移動先\\ファイル名
上記のようにする必要があるわけです。今回のxとmove_pathは次のようになっています。
【x】C:\\移動元パス\\ファイル名
【move_path】C:\\移動先パス1\\
xにはパスとファイル名が含まれていて、move_pathはパスだけを示しています。
移動元についてはxがそのまま使えますが、移動先についてはパスはあれどファイル名がありません。ファイル名はxのファイル名を抽出して活用します。つまり、移動先はxとmove_pathの組み合わせで作られることになります。
xとmove_pathを組み合わせて移動先のパスを作るには、xのファイル名の直前のパスの区切り以降の文字列を抽出、つまり絶対パスの中からファイル名だけ抽出して、移動先のパスにあたるmove_pathの後ろに付け足せばいいのです。
ファイル名を抽出するために、x[x.rfind('\\')+1:]としています。これは先ほど説明したスライスとrfindメソッドの抽出方法とほぼ同じで、違いは終了インデックスが省略されている点です。
開始・終了は省略することが可能で、省略した場合は端まで(最初または最後まで)が対象となります。つまり、『開始位置から最後まで』という範囲になります。こうすることで絶対パスの文字列からファイル名だけを抜き出すことができます。
【x[x.rfind('\\')+1:]】ファイル名
【move_path】C:\\移動先パス1\\
↓
【move_path+x[x.rfind('\\')+1:]】C:\\移動先パス1\\ファイル名
結果的に、move_pathとx[x.rfind('\\')+1:]を足すことで移動先の正確なパスが出来上がります。
print(x, 'を 【', move_path, '】へ移動しました')
ファイルを移動したら『○○を○○へ移動しました』とテキストが表示されるように設定しています。どのファイルが、どこからどこへ移動したのか視覚的にわかるようにしています。テキストを表示しなくていいというのであれば、この1行を削除しても問題ありません。削除したからといってプログラムに影響はありません。
独自定義関数の呼び出しと移動先パスの指定
file_move('C:\\移動先パス1\\')
file_move('C:\\移動先パス2\\')
これは独自定義関数file_moveの呼び出し記述です。ここで関数を実行することになります。カッコ内には移動先のパスを指定することになっています。移動先を増やしたいなら記述をコピペして任意の場所のパスを指定してください。減らしたいならその行を削除してください。
input('''Enterキーを押してください''')
input(
'''
Enterキーを押してください
'''
)
これは【プログラムの使い方】の時にも説明した通り、行動を促す働きをします。input()で何かしらの入力を促して、カッコの中はその時に表示するテキストを設定しています。