ファイルシステム

利用しているOS(Operating System)におけるファイル管理操作はPythonからも可能である。 ファイルは階層構造をなすディレクトリフォルダ)と呼ばれるコンテナの中にある。 この階層構造をディレクトリ・ツリーといい、このようにしてファイルを管理する仕組みをファイルシステムと呼ぶ。

ディレクトリの中に「子」ディレクトリ)およびファイルを格納することができ、ディレクトリ自身も「親」ディレクトリに格納されている。 ディレクトリツリーの頂点にあってすべてのディレクトリを格納しているコンテナをルート・ディレクトリという。

OSによらず、 現在作業しているディレクトリをカレント・ディレクトリとして1つのコンマ記号『.』で、親ディレクトリを2つのコンマを並べた記号『..』()で表す。

ファイルはファイルシステム内のあるディレクトリ内に格納されている。 目的ファイルを指定するために「通過する」ディレクトリを含めた指定をファイル・パスという。 絶対ファイルパスとはルートディレクトリからの目的ファイル位置指定、相対ファイルパスとはカレント・ディレクトリから目的ファイル位置指定である。

モジュール os

path が実在するディレクトリかファイルを参照しているときにTrue を返す。
モジュール os の主な機能
記述意味
os関係
os.getcwd()カレントディレクトリを返す。
os.listdir()path で指定されたディレクトリ内にあるエントリ名のリストを返す。リスト内の順番は不定。
os.chdir(path)現在の作業ディレクトリをpathに移動。pathは存在している(相対または絶対)ディレクトリパスでなければならない。
os.mkdir(path)ディレクトリpathの要素末尾の名前でディレクトリを作成。末尾より前の(相対または絶対)ディレクトリパスは既に存在してなければならない。
os.path関係
os.path.basename(path)指定したpathの末尾(最下層)のファイル名またはディレクトリ名。
os.path.abspath(path)指定した相対パスpathを絶対パス名に拡張。
os.path.dirname(path)指定したpathのの末尾(最下層)のファイルまたはディレクトリを含むディレクトリ名。
os.path.join(path, *paths)pathと2つ以上のパスの要素をディレクトリ区切り文字 (os.sep)を付けて結合したパスを返す。
os.path.split(path)path を (head, tail) のペアに分割。 tail はパス名の構成要素の末尾で tail はパス区切り記号('/'または'\\')を含まず、 head はそれより前の部分。 path がスラッシュで終わっていれば tail は空文字列に、もし path にスラッシュがなければ head は空文字になる。
os.path.exists()
os.path.isdir()path が実在するディレクトリを参照するなら True を返す。
os.path.isfile()path が実在するファイルを参照するなら True を返す。

パスの区切り文字はWindows系(バックスラッシュ「\」)とunix系(スラッシュ「/」)と表される違いがある(Pythonのせいではない)。 Python Shellで確かめてみよう。 まず、モジュール osをインポートしておく。 os.sep にパスの区切り文字が格納されている。

>>> import os
>>> os.sep
'/'        <--- macOSのパス区切り
'\\'       <--- Windowsのパス区切り

スクリプトを実行しているコマンド python を起動したカレント・ディレクトリを確認してみよう。 以下はmacOSの例である。

>>> os.getcwd()
'/Users/hoge/Documents/program/python'

実行しているPythonのファイルパスを含めたスクリプト名は、次のようにして組込みの特殊変数組み込みの変数 __file__ によって取得できる。

    # -*- coding: utf-8 -*-
import os

# 実行中のファイル名だけ
print(os.path.basename(__file__))
# 実行中のファイルを含むディレクトリパスだけ
print(os.path.dirname(__file__))
次のスクリプト os_sys.py は Python で スクリプトのファイルパス を 取得する基本コード (メモ)を参考にした。
# -*- coding: utf-8 -*-
import os, sys

print("スクリプトを実行しているカレントディレクトリの絶対パス:")
print("os.getcwd() : {0}".format(os.getcwd()))
print("---------------------------------")

print("実行中スクリプトのファイル名:")
print("os.path.basename(__file__) : {0}".format(os.path.basename(__file__)))
print("---------------------------------")

print(u"実行中スクリプト __file__ の相対パス:")
print("__file__ :{0}".format(__file__))
print("sys.argv[0] :{0}".format(sys.argv[0]))
print("---------------------------------")

print("実行中スクリプト __file__ の絶対パス:")
print("os.path.abspath(__file__) : {0}".format(os.path.abspath(__file__)))
print("---------------------------------")

print(u"実行中スクリプト --file__ の配置先ディレクトリの相対パス:")
print("os.path.dirname(__file__) : {0}".format(os.path.dirname(__file__)))
print("---------------------------------")

print("実行中スクリプト --file__ の配置先ディレクトリの絶対パス")
print("os.path.abspath(os.path.dirname(__file__)) : {0}".format(os.path.abspath(os.path.dirname(__file__))))
print("---------------------------------")

print("実行中スクリプト __file__ の配置先ディレクトリ内にあるファイルcat.pyの相対パス:")
cat_filepath = os.path.join(os.path.dirname(__file__), 'cat.py')
print("os.path.join(os.path.dirname(__file__), 'cat.py') : {0}".format(cat_filepath))
print("---------------------------------")

print("実行中スクリプト __file__ の配置先ディレクトリにあるcat.pyファイルの絶対パス:")
print("os.path.abspath(cat.py) : {0}".format(os.path.abspath(os.path.join(os.path.dirname(__file__),'cat.py'))))
print("---------------------------------")

print("cat.py の ファイルを1行づつ読み込んで表示:")
fp = open(cat_filepath, 'r')
for line in fp:
    print(line)
上のスクリプト os_sys.py を次の環境下で実行してみよう。 次のように、Pythonを起動するカレントディレクトリは /Users/hoge/Documents 、実行する目的スクリプトの相対パスは program/python/os_sys.py とする。
$ pwd
/Users/hoge/Documents
$ tree
.
├── program
│   ├── python
│   │   ├── cat.py
│   │   ├── os_sys.py.py
│   │   ├── project
│   │   │      ├──
以上の状況のもとで、スクリプト os_sys.py を実行して以下を得る。
$ python python/os_sys.py
スクリプトを実行しているカレントディレクトリの絶対パス:
os.getcwd() : /Users/hoge/Documents
---------------------------------
実行中スクリプト __file__ のファイル名:
os.path.basename(__file__) : os_sys.py
---------------------------------
実行中スクリプト __file__ の相対パス:
__file__ :python/script/os_sys.py
sys.argv[0] :program/python/os_sys.py
---------------------------------
実行中スクリプト __file__ の絶対パス:
os.path.abspath(__file__) : /Users/hoge/Documents/program/python/os_sys.py
---------------------------------
実行中スクリプト __file__ の配置先ディレクトリの相対パス:
os.path.dirname(__file__) : program/python
---------------------------------
実行中スクリプト __file__ の配置先ディレクトリの絶対パス
os.path.abspath(os.path.dirname(__file__)) : /Users/hoge/Documents/program/python
---------------------------------
実行中スクリプト__file__の配置先ディレクトリ内にあるファイルcat.pyの相対パス:
os.path.join(os.path.dirname(__file__), 'cat.py') : program/python/cat.py
---------------------------------
実行中スクリプト__file__の配置先ディレクトリにあるcat.pyファイルの絶対パス:
os.path.abspath(cat.py) : /Users/hoge/Documents/program/python/cat.py
---------------------------------
cat.py の ファイルを1行づつ読み込んで表示:
....
....

ファイルの確認

プログラム内で指定したファイルやディレクトリがなければ、処理に失敗し実行時エラーを生じてしまう。 Pythonでは実行時エラーを回避するために例外処理:実行時エラーを避ける仕組みが整っている。 モジュール os を使うとファイルやディレクトリの存在を検出することができる。

os.path.exists() を呼び出すと指定したファイルやディレクトリの両方の有無をTrue/Falseとして検出できる。

>>> import os
>>> os.path.exists('.')
True
>>> os.path.exists('..')
True
>>> os.path.exists('program/python')
True
>>> os.path.exists('program/sidewinder')
False
>>> os.path.exists('program/python/cat.py')
True

os.path.exists()の結果がTrueとなったとしても、指定したパス名がディレクトリあるいはファイルのどちらを参照しているかは分からない。 os.path.isdir() あるいは isfile() はパス名の参照先がディレクトリかファイルかをTrue/Falseとして返す。

>>> import os
>>> os.path.isdir('program/python')
True
>>> os.path.isdir('program/python/cat.py')
False
>>> os.path.isfile('program/python/cat.py')
True
次の簡単なプログラム list.py は引数で指定したディレクトリ内のファイルおよびディレクトリを出力する。
# -*- coding: utf-8 -*-
import sys, os

for file in os.listdir(sys.argv[1]):
    print(file)

文字列が文字列が指定した文字列 suffix で終わるなら True を返す文字列メソッド endswith(suffix) を使うと、次のようなカレントディレクトリにある拡張子 .py を持つファイルまたはディレクトリを出力するプログラムが書ける。

# -*- coding: utf-8 -*-
import sys, os
for file in os.listdir("./"):
    if file.endswith(".py"):
        print(file)
演習: 上のプログラムにおいて、拡張子 .py を持つ「本当のファイル」(ディレクトリでない)を書き出すように修正しなさい。