おはようございます。ITO です。
最近は情報社会ですね。
情報社会といえばフォルダです。
PYTHON でファイルやフォルダを扱うことは多々あります。エクセルや CSV を読み込んで処理したり、あるフォルダ内の画像ファイルに対して一括で処理したり。。。。
指定するファイルやフォルダのパスをソースコードの中に書いておいてもいいのですが、対象のファイルがよく変わる場合は毎回書き換えるのは面倒です。
そんなときは対象ファイルを GUI (グラフィカルユーザーインターフェース) で指定する方がラク。
そこで、よく見るファイル選択のダイアログを Python で使う方法のまとめもです!
環境は Python 3.7 です。
2023年7月24日(月) 追記
パソコンにインストールしている Python をバージョンアップしたので私の環境は python 3.11 になりました。3.7 時代のコードで問題なく動いています。
ファイルを選択
ファイル選択するダイアログを表示するために tkinter.filedialog モジュールの askopenfilename 関数を利用します。
ファイルをひとつ選択
まずはファイル選択。
import tkinter.filedialog
target_file = tkinter.filedialog.askopenfilename(filetypes=[("Excel ブック", "*.xlsx")])
引数は filetypes のみ設定しています。これにより、選択するファイルの種類を指定できます。ここで指定したファイルしかダイアログには表示されません。
filetypes には タプル (ラベル, パターン) の リスト [(ラベル1, パターン1), (ラベル2, パターン2), (ラベル3, パターン3), … ] を与えます。
パターン部分にはワイルドカード (*) が使えます。
戻り値としてダイアログで選択したファイルのパスが返されます。
実行したら以下ようなのウィンドウが出てきます!
上の例のフォルダにはダイアログで表示されている2つのファイル以外にもファイルがあるのですが、パターンでを “*.xlsx” としているので拡張子が xlsx のファイルしか選択できません!
パターンの部分でファイルの種類を絞っているのでラベルはなんでもオッケーです。
ちなみにパターン部分の拡張子より前のワイルドカードは書かなくてもオッケーです。
import tkinter.filedialog
filetypes = [("えくせるぶっく", "*.xlsx"), ("マクロありぶっく", ".xlsm"), ("CSVふぁいる", ".csv")]
target_file = tkinter.filedialog.askopenfilename(filetypes=filetypes, title="ファイルをひらく")
これを実行すると以下のようなダイアログでが表示されます。
filetypes を複数指定しているのでその分プルダウンで選択できるようになってます。title も設定しているのでウィンドウの左上に表示されてます!
不要なウィンドウ
ところで、先ほど紹介したソースコードだけを実行すると、ファイルダイアログ以外にも小さなウィンドウが出てきてると思います。
このウィンドウは tkinter のルートウィンドウと呼ばれるものだそうで、tkinter モジュールをインポートして、以下のようにコードを書くと消えます。
import tkinter as tk
import tkinter.filedialog
def dialog_test():
# ルートウィンドウ作成
root = tk.Tk()
# ルートウィンドウの非表示
root.withdraw()
# ファイル選択
filetypes = [("データファイル", "*.xlsx *.xlsm *.csv"), ("Excel ブック", "*.xlsx"), ("Excel マクロ有効ブック", "*.xlsm"), ("CSV (コンマ区切り)", "*.csv")]
target_file = tkinter.filedialog.askopenfilename(filetypes=filetypes, title="ファイルをひらく")
def main():
dialog_test()
複数ファイルを選択
複数ファイルの選択が可能なダイアログの表示は askopenfilenames 関数を使います。
使い方はさっき登場した askopenfilename 関数とほぼ同じです。引数もほぼ同じ。
というのも、askopenfilenames 関数は内部的に askopenfilename 関数のパラメータ multiple に 1 を与えて呼び出しているからです。
戻り値はファイルパスのタプルです。
引数 (オプション)
オプションなのですべて省略可能です。ファイル選択ダイアログ使用時に指定しそうな引数のみ書いてます。
parent
ダイアログを表示する親ウィンドウの指定。
tkinter で複数のウィンドウをを表示しているときにどのウィンドウの上にダイアログを出すかを指定できる。
tkinter の他のウィンドウは使わずに選択ダイアログだけを使う場合は気にしなくてOK。
title
ダイアログウィンドウの左上に表示されるタイトルの指定。
initialdir
ダイアログを表示したときに最初に開く場所 (ディレクトリ) の指定。
指定しなかったら前回 tkinter で表示した場所や環境ごとの初期ディレクトリが開かれる。
filetypes
上で書いた通り、選択できるファイルの種類の指定。
タプル (ラベル, パターン) の リスト [(ラベル1, パターン1), (ラベル2, パターン2), (ラベル3, パターン3), … ] を与える。
multiple
複数選択しない場合は 0 または False を、複数選択する場合は 1 または True を指定。
複数選択するときは 1 か True じゃなくても、0 、 False 以外を与えればいけます。
askopenfilename(multiple=1) と askopenfilenames() は同じ働きです。
フォルダを選択
フォルダ選択には tkinter.filedialog モジュールの askdirectory 関数を使います。
ファイル選択のときとだいたい同じで、askopenfilename が askdirectory に変わっただけです。
import tkinter.filedialog
target_dir = tkinter.filedialog.askdirectory()
実行するとフォルダ選択のダイアログが出てきます。
戻り値は選択したフォルダのパスです。キャンセルした場合は空の文字列。
引数 (オプション)
ファイル選択のときよりオプションは少なめ!
parent
ダイアログを表示する親ウィンドウの指定。
tkinter で複数のウィンドウをを表示しているときにどのウィンドウの上にダイアログを出すかを指定できる。
tkinter の他のウィンドウは使わずに選択ダイアログだけを使う場合は気にしなくてOK。
title
ダイアログウィンドウの左上に表示されるタイトルの指定。
initialdir
ダイアログを表示したときに最初に開く場所 (ディレクトリ) の指定。
指定しなかったら前回 tkinter で表示した場所や環境ごとの初期ディレクトリが開かれる。
mustexist
選択するフォルダの存在が可能かどうか。つまり存在しないフォルダの選択が可能かどうか。
True で存在が必須。なので存在しないフォルダを選択すると警告がでます。
デフォルトでは True となっています。
False なら存在しないフォルダを選択しても OK 、、、、、だと思って実行したらなぜか警告がでました。python のバージョンの問題なのか?今は分かりません。
選択したフォルダ内のファイルを取得
askdirectory 関数でゲットしたフォルダ内にあるファイルのパスも取得したくなりました。
そんなときは glob モジュールの glob 関数を使います。
import os
import tkinter as tk
import tkinter.filedialog
import glob
def dialog_test():
# ルートウィンドウの非表示
root = tk.Tk()
root.withdraw()
# フォルダ選択
target_dir = tkinter.filedialog.askdirectory(mustexist=True)
# フォルダ内の全ファイルを取得
files = glob.glob(os.path.join(target_dir, "*"))
for filepath in files:
print(filepath)
def main():
dialog_test()
glob 関数の引数に取得したいファイルのパターンのパス (日本語おかしいかも) を与えないといけません。
あるディレクトリ内のファイルをすべて取得する場合は
glob(“directory/*”)
のようにしないといけません。
なので 15 行目のように askdirectory で得たディレクトリのパスと “*” をジョインしてます!
しっかりとすべてのファイルが取得できています。
ちなみに特定のファイルだけを取得したい場合は
glob(“directory/ 取得したいファイルのパターン “)
のようにします。
例えばエクセルファイルを取得したい場合は
glob(“directory/*.xlsx”)
のようにします。
import os
import tkinter as tk
import tkinter.filedialog
import glob
def dialog_test():
# ルートウィンドウの非表示
root = tk.Tk()
root.withdraw()
# フォルダ選択
target_dir = tkinter.filedialog.askdirectory(mustexist=True)
# フォルダ内のエクセルファイルを取得
excelfiles = glob.glob(os.path.join(target_dir, "*.xlsx"))
for filepath in excelfiles:
print(filepath)
def main():
dialog_test()
これを実行すると、、、
ちゃんとエクセルファイルだけが取得できています!
ちなみに、フォルダ内の指定したファイルをサブフォルダ内も含めてすべて取得する方法は下記のページで紹介しています。
コメント