4-3. コンピュータにおけるファイルやディレクトリの配置

木構造のデータ形式について説明します。 この内容はPython言語に限らず、WindowsやMac、Linuxなどの一般的なOSにおいて共通する概念です。 Colaboratoryでは、同様の構造が仮想環境上に作られます。

みなさん、Windowsではエクスプローラ、MacではFinderを使ってファイルを階層的に保存していますよね。

下の例では、Windowsで ドキュメントDocuments) という名前のフォルダの中に Python入門 というフォルダを作り、 その下にこの教材を置いた時の、エクスプローラの様子を表しています。

fig/Explore.png

これは Jupyter Notebook では以下のように見えます。

fig/jupyterTree.png

このようなデータ形式は以下のような図で表すこともできます。 まるで木を逆さにしたような形に見えますね。 ですからこのようなデータの形式を「木構造」と呼びます。

また、一番根っこにあたるデータを「ルート(根)」、先端にあたるデータを「リーフ(葉)」、その間にあるデータを「ノード(節)」と呼びます。

fig/jupyterTreeIllust.png

データの保存においては、ファイルはリーフ(葉)に相当し、フォルダはノード(節)に相当します。 ルートはハードディスクやUSBメモリなど記録媒体自体に対応することが多いです。 ハードディスクに入っているファイルと、USBメモリに入っているファイルは、それぞれ違う木に属するデータということです。

カレントディレクトリ

4-1で sample.txt という名前のファイルをオープンするときに、以下のように書きました。

f = open('sample.txt', 'r')

このとき、この sample.txt というファイルはどこにあるのでしょうか?

実は、プログラムを実行するときは、どこかのディレクトリをカレントディレクトリとしています。 Jupyter Notebook では、そのノートブックが置かれているディレクトリをカレントディレクトリとします。 Colaboratoryでも同様です。

sample.txt が、このノートブックと同じディレクトリの中に置かれているならば(実際、置かれています)、 上のようにして sample.txt を開くことができました。

一方、novel.txt はこのノートブックと同じフォルダではなく、そこに置かれた text という名前のフォルダの中に 置かれているファイルです。 ですから、そのままファイル名だけを指定して開こうとすると以下のようにエラーが出て、ファイルのオープンに失敗します。

f = open('novel.txt', 'r', encoding='utf-8')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-1-6094f6eff0eb> in <module>
----> 1 f = open('novel.txt', 'r', encoding='utf-8')

FileNotFoundError: [Errno 2] No such file or directory: 'novel.txt'

ではどうやったら「カレントディレクトリの下の text の下」にある「novel.txt」を開けるのでしょうか?

これは次のように行います。

f = open('text/novel.txt', 'r', encoding='utf-8')

このようにすることによって、「カレントディレクトリの下の text の下にある novel.txt を開いてください」と指示することができます。

これは、カレントディレクトリから「novel.txt」までの経路(行き方)を表したものなのでパスとも呼びます。

[1]:
f = open('text/novel.txt', 'r', encoding='utf-8')
print(f.read())
f.close()
二人の若い紳士が、すつかりイギリスの兵隊のかたちをして、ぴか/\する鉄砲をかついで、白熊のやうな犬を二疋つれて、だいぶ山奥の、木の葉のかさ/\したとこを、こんなことを云ひながら、あるいてをりました。
「ぜんたい、こゝらの山は怪しからんね。鳥も獣も一疋も居やがらん。なんでも構はないから、早くタンタアーンと、やつて見たいもんだなあ。」
「鹿の黄いろな横つ腹なんぞに、二三発お見舞まうしたら、ずゐぶん痛快だらうねえ。くる/\まはつて、それからどたつと倒れるだらうねえ。」

相対パスと絶対パス

text/novel.txt という表現では、カレントディレクトリから novel.txt までのパスを表しています。 ここで、カレントディレクトリはノートブックの場所になるので、 どの場所に置かれたノートブックを開いているかによってカレントディレクトリが変わり、 それに応じて、同じファイルでもパスが変わります。

このようなパスの表現を相対パスと呼びます。

一方、

  • Windowsの場合: C:\Users\hagiya\Douments\Python入門\novel1.txt

  • macOSの場合: /Users/hagiya/Documents/Python入門/novel1.txt

のように、ルートからのパスを記した場合、 カレントディレクトリの場所に関わらず、常に同じファイルを指すことができます。

このようなパスの表現を絶対パスと呼びます。

ところで、カレントディレクトリより下にあるファイルは、 そこまでに入るディレクトリ名を(Windowsであっても)/ で区切って書けばよいですが、 その下にないファイルを指すにはどうしたらよいでしょうか?

たとえば下の図のようにカレントディレクトリが

  • Windows: C:\Users\hagiya\Douments\Python入門

  • macOS: /Users/hagiya/Documents/Python入門

のとき、

  • Windows: C:\Users\hagiya\Douments\メディアプログラミング入門\imagelist.csv

  • macOS: /Users/hagiya/Douments/メディアプログラミング入門/imagelist.csv

を開きたい場合はどうしたらよいでしょう?

fig/jupyterTreeIllust2.png

実は、1つ上のディレクトリを ..(ピリオド2つ)で表現することができます。 上の例だと、

f = open('../メディアプログラミング入門/imagelist.csv', 'r')

とすれば、

  • Windows: C:\Users\hagiya\Douments\メディアプログラミング入門\imagelist.csv

  • macOS: /Users/hagiya/Douments/メディアプログラミング入門/imagelist.csv

を開くことができます。 .. によって、Python入門 から1段上の Documents に戻り、 そこから メディアプログラミング入門 の下の imagelist.csv と辿っているわけです。

木構造によるデータ表現

木構造はファイルやディレクトリの保存形式だけでなく、データの表現として幅広く利用されます。 たとえば家系図も木構造による表現です。「家系図」は英語で “family tree” ですよね。

fig/FamilyTree.png

このような構造を持つデータでは、まるで家系図のように、 上位下位関係にあるデータ同士を「親子 (parent/child)」と呼んだり、 同位関係にあるものを「兄妹 (sibling)」と呼んだりします。 「祖先 (ancestor)」や「子孫 (desendant)」という表現も使われます。

データのこのような表現は、実際に親子関係にあるかは関係ありません。 たとえば下の図は四肢動物の系統樹です。

fig/PhylogeneticTree.png

データ構造的には、「有羊膜類」と「哺乳類」は親子関係にあるというわけです。

[ ]: