概要
数年間乱雑にスマホの画像をPCに移行し続けたせいで、写真の整理が手動では手に負えない状況になってしまいました。そこで今回は、ファイルを作成日時別にフォルダに分けてくれるプログラムを作ってみたいと思います。使用した言語はpythonです。
pythonは詳しくないので専門用語等は間違えてしまうかもしれませんが悪しからず。
プログラムの全容
まずディレクトリ構造を記載しておきます。
folder/
├ image
├ newFolder/2023/7
├ fileSorter.py
imagの中に仕分けをしたいファイルたちをぶち込んでおき、fileSorter.pyを実行することでnewFolderの中に月別にフォルダ分けされたファイルを格納します。newFolderは自動で生成されるので手動で作らなくても良いです。
仕組みとしては、
-
imageの中にあるファイルの詳細情報を取得
-
1の詳細情報をもとにnewFolderの中に年別と月別にフォルダを生成させる
-
image内のファイルを作成日時が適応するフォルダに適当に入れてあげる
という3段階になります。正確にはファイルの数だけ1から3までのステップをfor文で行います。
下準備
使用するライブラリをインポートする
今回使用するライブラリは以下の3つです。
import os
import time
import shutil
ファイル名を取得
まずは仕分けをしたいファイル名をすべて取得してlistにまとめます。とりあえず下のような感じです。
readPath = 'image'
readFiles = os.listdir(readPath)
定数のreadPathはfileSorter.pyからimageフォルダへの相対パスを定義してあげています。os.listdir(readPath)は引数の相対パスに該当するディレクトリ内にあるファイル名をリスト化してくれる関数です。
newFolderを作成
次に仕分けされたファイルを格納するためのnewFolderを生成します。正直もとから手動で作っても問題はありませんが、pathを間違えるとめんどくさいので自動生成することにしました。
newDirPath = 'newFolder'
try:
os.mkdir(newDirPath)
except FileExistError:
pass
newDirPathでnewFolderへの相対パスを定義して、os.mkdir(newDirPath)で引数の相対パスに対応するようにnewFolderを生成します。コードを実行したときに既にnewFolderが生成されている場合エラーが発生するためtryを使っています。
これで下準備は出来ました。
ファイルの詳細情報を取得
ここからはfor文でファイル一つひとつをnewFolderの中に移動させるプログラムを作成していきます。そのためにまずはfor文の中にファイルの詳細情報を取得するプログラムを書きます。
for readFile in readFiles:
readFilePath = readPath + '/' + readFile
year = str(time.localtime(os.path.getmtime(readFilePath))[0])
month = str(time.localtime(os.path.getmtime(readFilePath))[1])
このfor文はreadFilesに格納されているファイル名のリストを1つずつ参照していきます。まずは参照したいファイルのパスをreadFilePahに定義しておき、これを利用して参照ファイルの更新日時の年と月を取得しています。os.path.getmtime()は引数のパスに対応するファイルのタイムスタンプを取得しますが、調べた感じUNIX timestampという値が返されるようなので、time.localtime()でローカルタイムに変換しています。time.localtime()はたとえば
time.struct_time(tm_year=2023, tm_mon=6, tm_mday=17, tm_hour=4, tm_min=35, tm_sec=38, tm_wday=2, tm_yday=137, tm_isdst=0)
のようなtime.struct_timeというクラスとして返ってきます。この中でほしい値はtm_yearとtm_monなのでリスト番号を振って取得しています。定義したいyearとmonthという定数はあとでフォルダ名として使いたいため、データタイプをintからstringに変換しておきます。
ちなみに、今回は作成日時ではなく更新日時をもとにファイル分けをすることにしましたが、作成日時をもとにデータを取得したい場合はWindows環境ではgetmtimeではなくgetctimeを使えばいいようです。
newFolderの中に年別と月別にフォルダを生成させる
続いてnewFolderの中に年別と月別にフォルダを生成させます。以下のコードはfor文の中に書きます。
yearDirPath = newDirPath + '/' + year
monDirPath = yearDirPath + '/' + month
try:
os.mkdir(yearDirPath)
except FileExistsError:
pass
try:
os.mkdir(monDirPath)
except FileExistsError:
pass
年と月のディレクトリを作るために相対パス名を定義しておき、os.mkdir()でフォルダを作成します。for文を回していると既にフォルダが存在する可能性があるのでエラー対策としてtry文を使います。
image内のファイルを適当なフォルダに入れてあげる
あとは作成したフォルダに移してあげるだけなので、
shutil.move(readFilePath, monDirPath + '/' + readFile)
を追記します。引数のひとつ目が始動させたいファイルのパスで、二つ目が移し先のパスになっています。2つ目の引数にreadFileまで書き込むと、既に同じファイルが移動先にあった場合でもエラーが起きません。
全体像
import shutil
import time
import os
readPath = 'image'
readFiles = os.listdir(readPath)
newDirPath = 'newFolder'
try:
os.mkdir(newDirPath)
except FileExistsError:
pass
for readFile in readFiles:
readFilePath = readPath + '/' + readFile
year = str(time.localtime(os.path.getmtime(readFilePath))[0])
month = str(time.localtime(os.path.getmtime(readFilePath))[1])
yearDirPath = newDirPath + '/' + year
monDirPath = yearDirPath + '/' + month
try:
os.mkdir(yearDirPath)
except FileExistsError:
pass
try:
os.mkdir(monDirPath)
except FileExistsError:
pass
shutil.move(readFilePath, monDirPath + '/' + readFile)
一応これで完成なのですが、場合によってはもともとのファイルを消したくないこともあるかもしれないのでコマンド操作で元データを消去するかしないかを変更できるようにします。
import shutil
import time
import os
readPath = 'image'
readFiles = os.listdir(readPath)
newDirPath = 'newFolder'
try:
os.mkdir(newDirPath)
except FileExistsError:
pass
print("Are you planning to delete original files?")
print("if Yes, please enter 'y', and if No, please enter any command other than'y'")
arg = input('>>')
for readFile in readFiles:
readFilePath = readPath + '/' + readFile
year = str(time.localtime(os.path.getmtime(readFilePath))[0])
month = str(time.localtime(os.path.getmtime(readFilePath))[1])
yearDirPath = newDirPath + '/' + year
monDirPath = yearDirPath + '/' + month
try:
os.mkdir(yearDirPath)
except FileExistsError:
pass
try:
os.mkdir(monDirPath)
except FileExistsError:
pass
if arg == 'y':
shutil.move(readFilePath, monDirPath + '/' + readFile)
else:
shutil.copy2(readFilePath, monDirPath)
途中で
arg = input('>>')
を書いておき、最後のif文でarg='y'のときはカット&ペーストをしてもらい、それ以外ではコピペをしてもらうようにしました。コマンド操作はおそらくipynb形式ではできないので、py形式でコードを保存しています。
課題
今回はファイルを移動させると作成日時も更新されてしまうため、もともとの作成日時を継承させることができませんでした。暇なときにでも作成日時も継承できる方法を模索してみようと思います。