この第 1 版は Lua 5.0 向けに執筆されました。依然として以降のバージョンで大きな関連性を持っていますが、いくつかの違いがあります。
第 4 版は Lua 5.3 を対象としており、Amazon やその他の書店でご利用いただけます。
書籍を購入することで、Lua プロジェクトのサポートにも役立ちます。


12 – データファイルと永続化

データファイルを処理する場合、データを書き出すことは通常、それらを読み戻すよりもはるかに簡単です。ファイルを書き出すとき、何が起こるかを完全に制御できます。その一方、ファイルを書き込むと、何が発生するかを知りません。正しいファイルに含まれる可能性のあるあらゆる種類のデータに加えて、堅牢なプログラムでは問題のあるファイルも適切に処理する必要があります。そのため、堅牢な入力ルーチンをコーディングすることは常に困難です。

第 10.1 節 の例で見たように、テーブルコンストラクタはファイル形式向けの興味深い代替オプションを提供します。データを書き出すときに少し余分な作業をすれば、読み取りが簡単になります。このテクニックは、データを Lua コードとしてデータファイルに書き込むというもので、実行されるとデータがプログラムに構築されます。テーブルコンストラクタを使用すると、これらのチャンクはプレーンなデータファイルのように見ることができます。

いつものように、例を見て明確にしましょう。データファイルが CSV (カンマ区切り値) などの定義済みの形式にある場合、選択肢はほとんどありません。(第 20 章 では、Lua で CSV を読み取る方法について説明します)。ただし、後で使用するファイルをこれから作成する場合、CSV の代わりに Lua コンストラクタを形式として使用できます。この形式では、各データレコードを Lua コンストラクタとして表します。次のようなものを書く代わりに

    Donald E. Knuth,Literate Programming,CSLI,1992
    Jon Bentley,More Programming Pearls,Addison-Wesley,1990
データファイルに書きます
    Entry{"Donald E. Knuth",
          "Literate Programming",
          "CSLI",
          1992}
    
    Entry{"Jon Bentley",
          "More Programming Pearls",
          "Addison-Wesley",
          1990}
Entry{...}Entry({...})、つまり引数にテーブルを使用した関数 Entry の呼び出しと同じであることに注意してください。したがって、この前のデータ部分は Lua プログラムです。このファイルを読み取るには、Entry の妥当な定義を使用するだけで実行できます。たとえば、次のプログラムはデータファイルのエントリ数をカウントします
    local count = 0
    function Entry (b) count = count + 1 end
    dofile("data")
    print("number of entries: " .. count)
次のプログラムは、ファイルで検出されたすべての著者の名前をセットとして収集してからそれらを出力します。(著者の名前は各エントリの最初のフィールドです。したがって、b がエントリ値の場合、b[1] は著者です)。
    local authors = {}      -- a set to collect authors
    function Entry (b) authors[b[1]] = true end
    dofile("data")
    for name in pairs(authors) do print(name) end
これらのプログラムフラグメントのイベント駆動型アプローチに注意してください。Entry 関数は、データファイル内の各エントリに対する dofile の間に呼び出されるコールバック関数として機能します。

ファイルサイズが問題にならない場合は、表現に名前と値のペアを使用できます

    Entry{
      author = "Donald E. Knuth",
      title = "Literate Programming",
      publisher = "CSLI",
      year = 1992
    }
    
    Entry{
      author = "Jon Bentley",
      title = "More Programming Pearls",
      publisher = "Addison-Wesley",
      year = 1990
    }
(この形式が BibTeX を連想させる場合、偶然ではありません。BibTeX は Lua のコンストラクタ構文のためのインスピレーションの 1 つでした)。この形式は、各データに意味の短い説明が添付されているため、自己記述形式のデータと呼ばれます。自己記述データは、CSV やその他のコンパクトな表記よりも (少なくとも人間にとって) 読みやすく、必要に応じて手動で編集しやすく、データファイルを変更せずに小さな変更を加えることができます。たとえば、新しいフィールドを追加する場合、フィールドが存在しないときに既定値を指定するように読み取りプログラムを少し変更するだけで済みます。

名前と値の形式では、著者の収集のためのプログラムは次のようになります

    local authors = {}      -- a set to collect authors
    function Entry (b) authors[b.author] = true end
    dofile("data")
    for name in pairs(authors) do print(name) end
これで、フィールドの順序に関係なくなります。エントリの一部に著者情報を指定していなくても、Entry
    function Entry (b)
      if b.author then authors[b.author] = true end
    end

Lua は高速に実行されるばかりでなく、コンパイルも高速です。たとえば、上記の著者情報を列挙するプログラムは、2 MB のデータで 1 秒未満で実行されます。繰り返しますが、これは偶然ではありません。データ記述は Lua の作成当初からの主要なアプリケーションの 1 つで、大規模チャンクに対してコンパイラを高速化するために細心の注意が払われました。