ストレージ

有用な情報を保存しなければならないこともあります。そのような情報はそれを表現するデータとして保存します(コンピュータに保存されるときのデジタル形式)。コンピュータにデータを保存すると、デバイスの電源を入れ直してもデータは保持されます。

幸い micro:bit の MicroPython では非常に単純なファイルシステムでこれを行うことができます。メモリの制約のため、ファイルシステムで 利用可能な容量は約 30KB となっています。

ファイルシステムとは何か?

ファイルシステムとは、データを永続的に格納・編成する手段です。ファイルシステムに格納されたデータは、デバイスの再起動後も残っている必要があります。名前が示すように、ファイルシステムに格納されたデータはファイルに編成されます。

../_images/files.jpg

コンピュータのファイルは、ファイルシステムに格納された名前付きのデジタルリソースです。そのようなリソースには、有用な情報がデータとして含まれています。これは、紙のファイルの仕組みとまったく同じです。それは有益な情報を含む一種の名前付きコンテナです。通常、紙でもデジタルでもファイルには名前が付けられています。コンピュータでは .something のような接尾辞をファイル名の終わりにつけるのが一般的です。通常、」something」 は情報を表すために使用されるデータのタイプを示します。たとえば .txt はテキストファイル、 .jpg は JPEG 画像、 .mp3 は MP3 としてエンコードされたサウンドデータを示します。

(ラップトップや PC のように)ファイルシステムによっては、ファイルをディレクトリにまとめることができます。これは名前付きびコンテナであり、関連するファイルとサブディレクトリをまとめてグループ化します。ただし、 MicroPython が提供するファイルシステムはフラットファイルシステムです 。フラットファイルシステムにはディレクトリがありません。すべてのファイルは同じ場所に保存されます(訳注: MicroPython がフラットファイルシステムであるという制限はあくまで BBC micro:bit での話です)。

Python プログラミング言語は、コンピュータのファイルシステムを操作するための使いやすく強力な方法を提供しています。micro:bit の MicroPython は、これらの機能の便利なサブセットを実装して、デバイス上のファイルを簡単に読み書きできるようにしています。また、他のバージョンの Python との一貫性も提供します。

警告

micro:bit にプログラムを転送すると、デバイスによって使用されるすべてのフラッシュメモリが書き換えられます。ファイルシステムがフラッシュメモリに再設定されるため、すべてのデータが破棄されてしまいます。

ただし、デバイスの電源を切っただけではデータはそのまま残り続けます。データが消えるのは、ファイルを削除するか、デバイスを再フラッシュした場合です。

開けゴマ(Open Sesame)

ファイルシステム上でのファイルの読み書きは、 open 関数によって実現されます。ファイルを開いたら、それを閉じるまでファイルの中身をいじれます(紙ファイルの使用方法に似ています)。ファイル作業の完了を MicroPython に知るには、ファイルを閉じることが不可欠です。

これを行う最も良い方法は、次のように with 文を使うことです:

with open('story.txt') as my_file:
    content = my_file.read()
print(content)

with 文は、open 関数でファイルを開き、開いたファイルをオブジェクトに割り当てます。上記の例では、 open 関数が story.txt (明らかに何らかのストーリーを含むテキストファイル)というファイルを開きます。Python コードでファイルを表現するために使われるオブジェクトには my_file という名前をつけています。その後、 with``文の下にインデントされたコードブロックで、 ``my_file オブジェクトは read() で内容を読み出され、読み出された内容は content に代入されます。

重要な点は次の行の print がインデントされていないことです。with 文に関連付けられたコードブロックは、ファイルを読み取る単一の行だけです。 with 文に関連付けられたコードブロックを抜けると、Python (および MicroPython)によって自動的にファイルが閉じられます。これはコンテキスト処理と呼ばれ、 open 関数はファイルのためのコンテキストハンドラを作成します。

簡単に言えば、ファイルとのやりとりの範囲は、ファイルを開いた with 文に関連付けられたコードブロックによって定義されます。

混乱してますか?

心配しないでください。コードは次のようになパターンになるというだけです:

with open('ファイル名') as some_object:
    # with 文のこのコードブロック内で
    # some_object をいじれます

# ブロックを抜けると MicroPython が
# 自動でファイルをクローズしてくれます

紙ファイルと同様にに、デジタルファイルは2つの理由で開きます。1つは(上に例示したように)ファイルの内容を読むこと、もう1つはファイルに何かを書き込むことです。デフォルトのモードはファイルを読むことです。ファイルに書き込む場合 open 関数には、次のように関数に指示する必要があります。

with open('hello.txt', 'w') as my_file:
    my_file.write("Hello, World!")

この 'w' 引数は、 my_file オブジェクトを書込みモードに設定するために使います。 'r' 引数でファイルオブジェクトを読み取りモードに設定することもできますが、これはデフォルトなので、省略することが多いです。

ファイルへのデータの書き込みには(推測どおりかもしれませんが) write メソッドを使います。ファイルに書き込む文字列を引数に指定します。上の例では、 「hello.txt」 というファイルに 「Hello、World!」 というテキストを書き込んでいます。

簡単!

注釈

ファイルを開いて書き込むとき、ファイルがすでに存在する場合はファイルの内容を上書きします。

ファイルにデータを追加するには、最初にそれを読み出し、読み出した内容をどこかに保持し、ファイルを閉じ、読み込んだ内容にデータを追加して、再度ファイルを開いて、改訂した内容を書き直す必要があります。

これは MicroPython の場合ですが、 「通常の」 Python では 「append」 モードで書き込むファイルを開くことができます。micro:bit でこれを行うことができないのは、ファイルシステムの実装を簡略化したためです。

OS SOS

Python には、ファイルの読み書き以外にもできるファイル操作があります。ファイルシステム上に何のファイルがあるかを知る必要があるでしょうし、またそれらを削除が必要になることもあるでしょう。

通常のコンピュータにおいて、オペレーティングシステム(Windows, OSX, Linuxなど)の役割は Python などのためにこのような管理をすることです。このような機能は Python では os というモジュールを介して利用できます。MicroPython はオペレーティングシステム でもある ため、 os モジュールの適切な機能を一貫性のあるものに保つことにしました。そのため、ラップトップや Raspberry Pi のようなデバイスで「通常の」Python を使う場合と同様の操作があります。

基本的に、ファイルシステムに関連する3つの操作、つまりファイルの一覧表示、ファイルの削除、ファイルのサイズの確認を行うことができます。

ファイルシステム上のファイルを一覧表示するには、 listdir 関数を使用します。これはファイルシステム上のファイルのファイル名を示す文字列のリストを返します:

import os
my_files = os.listdir()

ファイルを削除するには、 remove 関数を使用します。これは削除するファイルのファイル名を表す文字列を引数として指定します:

import os
os.remove('filename.txt')

最後に、ファイルを読む前にファイルの大きさを知ることが有用な場合もあります。これを行うには、 size 関数を使用します。 remove 関数と同様に、サイズを知りたいファイルのファイル名を表す文字列を指定します。この関数はファイルが占めるバイト数を示す整数を返します:

import os
file_size = os.size('a_big_file.txt')

ファイルシステムを操作するのはよいのですが、デバイスにファイルを出し入れする場合はどうしたらよいでしょうか?

microfs ユーティリティを使うだけです!

ファイル転送

BBC micro:bit のプログラミングに使うコンピュータに Python がインストールされているなら、microfs という特別なユーティリティを使えます(コマンドラインで使うときには ufs と短縮した名前を使います)。microfs のインストールと利用について詳しい手順は microfs のドキュメンテーション を参照してください。

ここでは、ほとんどこれだけで用が足りるという4つの基本コマンドだけを説明します:

$ ufs ls
story.txt

ls サブコマンドは、ファイルシステム上のファイルの一覧表示します(同じ機能を提供する一般的な Unix コマンド ls にちなんで名付けられています)。

$ ufs get story.txt

get サブコマンドは、接続した micro:bit からファイルを取得し、コンピュータの現在の場所に保存します(同じ機能を提供する一般的なファイル転送プロトコル [FTP] のコマンド get にちなんで名付けられています)。

$ ufs rm story.txt

rm サブコマンドは、接続した micro:bit から指定の名前のファイルを削除します(同じ機能を提供する一般的な Unix コマンド rm にちなんで名付けられています)。

$ ufs put story2.txt

put サブコマンドは、コンピュータから接続されたデバイスにファイルを置きます(同じ機能を提供する一般的なファイル転送プロトコル [FTP] のコマンド put にちなんで名付けられています)。

主役 main.py

ファイルシステムには興味深いプロパティがあります: MicroPython ランタイムだけをデバイスに転送した後で起動すると、何かを行うことを待っているだけです。ただし、 main.py という特別なファイルをファイルシステムにコピーして、デバイスを再起動すると、MicroPython はその main.py ファイルの内容を実行します。

さらに、他の Python ファイルをファイルシステムにコピーすると、他の Python モジュールと同様にそれを import できます。たとえば次の単純なコードを含むファイル hello.py があったとします。

def say_hello(name="World"):
    return "Hello, {}!".format(name)

これを次のようにインポートして say_hello 関数を使えます:

from microbit import display
from hello import say_hello

display.scroll(say_hello())

もちろん、 「Hello、World!」 というテキストが表示されます。重要な点は、この例では2つの Python モジュールに分割され、 import 文がコードを共有するために使われていることです。

注釈

MicroPython ランタイムに加えてデバイスにスクリプトを転送した場合、MicroPython は main.py 無視して、代わりに埋め込みスクリプトを実行します。

ランタイムだけを転送するには、エディタで作成したスクリプトに何も文字が含まれていないことを確認するだけです。転送されると、main.py」 ファイルをコピーすることができます。