連載

.NETで簡単XML

第15回 川俣流XMLプログラミングの定石(1)

株式会社ピーデー 川俣 晶
2004/03/06

安全なファイル書き込みのための定石

 これは本来ならXMLプログラミングとは関係のない定石ともいえるが、初心者や、データをRDBMSに保存することに慣れきったプログラマが引っかかる恐れのある問題なので、ここで取り上げることにする。ファイルとして保存されているXML文書を更新するときに、ディスクの残り容量が足りない場合の配慮である。この異常ケースは、しばしば対応を見落としがちになる。筆者も見落とすことがある。そのため、定石としていつも実行するように習慣付ける方がよいだろう。

 さて、本題に入ろう。どんなディスクであろうとファイルを書き込み続ければ、いつかディスクがいっぱいになり、残り空き容量が尽きてなくなる。RDBMSであれば、そのようなケースへの対策はきちんと取られていると思うので、ディスクに残り空き容量がない状態でデータを追加しようとしても、ただ追加が失敗するだけで、既存のデータが破壊されたりはしないはずである。

 しかし、XML文書にデータを追加するプログラムを以下のように安易に記述すると、致命的な問題を引き起こすことになる。

Private Const filename As String = "c:\sample.xml"

Private Sub insertData(ByVal number As Integer, ByVal count As Integer)
  Dim doc As XmlDocument = New XmlDocument
  doc.Load(filename)
  For i As Integer = 0 To count - 1
    Dim newElement As XmlElement = doc.CreateElement("data")
    newElement.InnerText = "Number " + (number + i).ToString()
    doc.DocumentElement.InsertBefore(newElement, doc.DocumentElement.FirstChild)
  Next
  doc.Save(filename)
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  insertData(0, 1000)
End Sub
サンプル・プログラム1:XML文書にデータを追加するプログラム(VB.NET版C#版

 これを実行する前に、「c:\sample.xml」というファイル名で以下のようなXML文書を作成しておく。

<root>
  <data>FirstData</data>
</root>
サンプル・プログラム1を実行する前に作成しておくXML文書
サンプル・プログラム1を実行する前に「c:\sample.xml」というファイル名でXMLファイルを作成しておく。

 そして、追加データをすべて書き込めなくなるほどCドライブの残り空き容量を少なくしておいてからこのサンプル・プログラムを実行すると、以下のような例外を発生させてプログラムは停止してしまう。

'System.IO.IOException' のハンドルされていない例外が mscorlib.dll で発生しました。

追加情報 : ディスクに十分な空き領域がありません。
ディスク書込時にディスクの残り空き容量が不足すると発生する例外
XML文書にデータを追加する場合に、そのXMLファイルのあるディスクの残り空き容量が足りないと、このような例外が発生してプログラムは停止する。

 ここで、「c:\sample.xml」を開いてみると、以下のような内容になっている。

<root>
  <data>Number 999</data>
  <data>Number 998</data>
  <data>Number 997</data>
  ……中略……
  <data>Number 851</data>
  <data>Number 850</data>
  <data>Number 849</data>
  <data>Num
残り空き容量が不足した状況でサンプル・プログラム1を実行した場合のXML文書の出力例
残り空き容量が不足した状況でサンプル・プログラム1実行すると、先ほど作成しておいたXMLファイルはこのような不完全なXMLファイルになってしまう。

 この結果は複数の問題を抱えている。

 まず第1に、このファイルはXML文書として正しくない。root要素の終了タグがなく、最後のdata要素の終了タグもない。つまりXML文書として読み込むことはできなくなっているわけである。そのため、この例外を見て、慌ててディスクの空き容量を拡大してからプログラムを再実行しても、このXML文書を読み込むときにエラーが発生するようになってしまう。

 また、このXML文書には、サンプル・プログラム1を実行する前に入っていた既存のデータが含まれていない。最初のXML文書には、「FirstData」というテキストが入っていたが、それはプログラム実行後に残されたXML文書のどこにも見あたらない。ディスクの空き容量が十分であれば、このテキストは、最後に出現するdata要素の内容となるはずだが、それを書き込む前にディスクが尽きてしまったわけである。このFirstDataというテキストは、もはやディスク上のどこにも残っておらず、メモリ上にあるDOMオブジェクトの中にしか残っていない。DOMオブジェクトが破棄されれば、永遠に失われてしまう。

 もちろん実用システムであれば、バックアップを取っておくのが常識だが、たとえそうであっても、バックアップを取った後に追加されたデータは戻ってこないことになる。

 さて、このような致命的な問題がいともたやすく発生するのは、XMLのFAQ(よくある質問)の1つである「XMLはDBMSではない」という事実に由来する。XMLとは、あくまで情報をマークアップするメタ言語であって、データを保存するストレージではない。だから、これまでRDBMSで行っていたことを、ファイル上のXML文書を使ってやろうとすると、RDBMSがやってくれていた多くの機能を、プログラマ自身が肩代わりして明示的に記述する必要が生じる。これに対処する望ましい方法は、XML文書をファイルに保存するのではなく、RDBMSに匹敵する安全性を持ったXMLデータベースに保存する方法であろう。しかし、それはちょっとしたデータの保存のためだけに高価なXMLデータベースを買えない、といったようなさまざまな理由により踏み切りにくい選択だろう。だが、この程度の問題であれば、多少のコードを追加することで対策することができる。


 INDEX
  .NETで簡単XML
  第15回 川俣流XMLプログラミングの定石(1)
    1.XMLプログラミングにおける定石の必要性
  2.XMLファイル書き込み時の問題点
    3.安全なXMLファイル書き込みのための定石
    4.XML文書の読み書きにどの方法を使うか
    5.シリアライズを使った読み書きの問題点
 
インデックス・ページヘ  「連載 :.NETで簡単XML」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間