No Programming, No Life

プログラミング関連の話題や雑記

Groovyでuseキーワードを使ってExcelのOpen-Close処理を楽にする

ScriptomでExcelファイルの内容の読み込み - No Programming, No Lifeid:re_shikajiroさんに

ExcelのOpen-Closeも new File(){} みたいにクロージャで書けたらきれいでしょうねー。

というコメントをいただいたので、useキーワードの使い方の練習も兼ねて作ってみました。re_shikajiroさん、thanksです。
(動作確認 Groovy Version: 1.5.7 JVM: 1.6.0_10)

カテゴリクラスの作成

Excelを操作する時のカテゴリクラスを以下のような感じで作成。

ExcelCategory.groovy
import org.codehaus.groovy.scriptom.*

/** エクセルカテゴリ */
class ExcelCategory {
   /** ファイルを読み込む */
   static void readXls(File self, Closure yield){
      Scriptom.inApartment{
         def excelApp  // Excelアプリケーション
         def workbooks // ワークブック
         try {
            // Excelアプリケーションを生成
            excelApp = new ActiveXObject('Excel.Application')
            // ワークブックを開く
            workbooks = excelApp.Workbooks.Open(self.canonicalPath)
            // 処理をクロージャに委譲
            yield(excelApp)
         } finally {
            // ワークブックを閉じる
            workbooks.Close()
            // Excelアプリケーションを閉じる
            excelApp.Quit()
         }
      }
   }

   /** ファイルを編集する */
   static void editXls(File self, Closure yield){
      Scriptom.inApartment{
         def excelApp  // Excelアプリケーション
         def workbooks // ワークブック
         try {
            // Excelアプリケーションを生成
            excelApp = new ActiveXObject('Excel.Application')
            // ワークブックを開く
            workbooks = excelApp.Workbooks.Open(self.canonicalPath)
            // 処理をクロージャに委譲
            yield(excelApp)
            // ワークブックを上書き保存
            workbooks.Save()
         } finally {
            // ワークブックを閉じる
            workbooks.Close()
            // Excelアプリケーションを閉じる
            excelApp.Quit()
         }
      }
   }
}

カテゴリクラスではstaticメソッドを宣言します。staticメソッドの第一引数に使用したいクラスを指定します。(今回の場合はjava.io.File)
#readXls(), #editXls()の中にExcelのOpen-Close処理およびScriptom.inApartment処理を閉じ込めました。

(追記: 2009-01-31)

  • 例外処理を追加しました。
  • 読み込み(#readXls())と編集(#editXls())を分離しました。編集の方は最後に上書き保存してくれます。
使用例

ExcelCategory.groovyをクラスパスの通った場所において置くことで以下のように使用できます。

use (ExcelCategory) {
  new File('hogehoge.xls').readXls{ excelApp ->
    // hogehoge.xlsに対する何かしらの処理
  }
}

use内(カテゴリ内)において限定的にFile#readXls(), File#editXls()が利用可能になりますので、エクセル操作をするクロージャをreadXls, editXlsに対して渡します。*1
ExcelCategory.groovyを別ファイルにすることで、使用する側ではscriptomのimportとかを書かなくてよいので、意外とすっきり。useキーワードを使うと拡張が限定的になるため、他のコードに迷惑をかけずに済むところがいいですね。

おまけ

以下は、Groovyでクラスの拡張 - No Programming, No LifeでやったみたいにFileクラスを拡張する方法です。

import org.codehaus.groovy.scriptom.*

// Fileを拡張
File.metaClass.readXls = { Closure yield ->
   Scriptom.inApartment{
      def excelApp  // Excelアプリケーション
      def workbooks // ワークブック
      try {
         // Excelアプリケーションを生成
         excelApp = new ActiveXObject('Excel.Application')
         // ワークブックを開く
         workbooks = excelApp.Workbooks.Open(delegate.canonicalPath)
         // 処理をクロージャに委譲
         yield(excelApp)
      } finally {
         // ワークブックを閉じる
         workbooks.Close()
         // Excelアプリケーションを閉じる
         excelApp.Quit()
      }
   }
}

// 使用してみる
new File('hogehoge.xls').readXls{ excelApp ->
  // hogehoge.xlsに対する何かしらの処理
}

(追記: 2009-01-31)

  • 例外処理を追加しました。

*1:クロージャで受け取る変数excelAppはorg.codehaus.groovy.scriptom.ActiveXObjectです。