Java の .properties ファイルってのを作成するための元データを Excel で管理していて、今までは Excel マクロ を使って .properties ファイルを作成していたんだけど、
ビルドプロセスの一環に組み込む事にしようってことで、Excel マクロだと権限の問題等があって何とかならないかな〜?と相談された。
そこで、「Groovy だったら Excel ファイルもサクッと扱えますよ」と自分で試した事も無いのに言ってみたら、じゃあ Groovy 使っていいよって事になったので勉強中。
こんな感じの Excel から
各言語毎に、.properties ファイルを作成したい。
日本語 | 英語 |
---|---|
ScriptomでExcelファイルの内容の読み込み - No Programming, No Life を参考にして何とか出来た!
import org.codehaus.groovy.scriptom.* def messages = [ ja : new Properties(), en : new Properties() ] Scriptom.inApartment { def excelApp def workBook try { excelApp = new ActiveXObject('Excel.Application') def fileName = "〜\\Message.xls" // ファイルを開く workBook = excelApp.workbooks.open(fileName) // セルに対しての操作 workBook.sheets(1).cells.with { def rowIndex = 2 def messageKey = cells.item(rowIndex, 1).value while (messageKey) { def japanese = cells.item(rowIndex, 2).value def english = cells.item(rowIndex, 3).value messages.ja.setProperty(messageKey, japanese) messages.en.setProperty(messageKey, english) rowIndex++ messageKey = cells.item(rowIndex, 1).value } } } finally { workBook?.close() excelApp?.quit() } } messages.each { entry -> entry.value.store(new File("〜\\Message_${entry.key}.properties").newOutputStream(), "$entry.key") }まだ、Groovy を使い慣れてないんだろうな〜。もっとスッキリ実装出来そうな気がする。。
注意する点は、Excel の quit メソッドが呼ばれないと Excel のプロセス が残ったままになる。これは、.NET から呼び出しても同じかな。
ただ .NET の場合使用した参照を全部保持して、System.Runtime.InteropServices.Marshal.ReleaseComObject メソッド で参照をデクリメントしないと Excel プロセスを解放しないので、Groovy の方が楽ちん!
ちなみに C# で COMで Excel を操作する場合のソース (メンドイので途中省略)(VSTO の場合は、ここまできっちり解放しなくても大丈夫なはず)
※遅延バインディング(Excelのバージョンを意識しない様に)を使ってるので、全部 Invoke 経由でのアクセスになってますが、
遅延バインディングでは無くても 全部 try〜finally で囲って ReleaseComObject メソッドを呼ばないとダメです。
また、try 〜 finally を全部一つにすると ReleaseComObject メソッドで例外が発生した場合、全て解放されないケースが出てくるので、一つずつ解放しないとダメなはずです。using System; using System.Reflection; namespace ConsoleApplication15 { class Program { static void Main(string[] args) { object excelApp = null; try { excelApp = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application")); object workbooks = null; try { workbooks = excelApp.GetType().InvokeMember("Workbooks", BindingFlags.Public | BindingFlags.GetProperty, null, excelApp, null); object workbook = null; try { workbook = workbooks.GetType().InvokeMember("Open", BindingFlags.Public | BindingFlags.InvokeMethod, null, workbooks, new object[] { @"〜\Message.xls" }); object sheets = null; try { sheets = workbook.GetType().InvokeMember("Sheets", BindingFlags.Public | BindingFlags.GetProperty, null, workbook, null); object sheet = null; try { sheet = sheets.GetType().InvokeMember("Item", BindingFlags.Public | BindingFlags.GetProperty, null, sheets, new object[] { 1 }); // Cells try { // Cell while(true) { try { } finally { } if (〜) { break; } } } finally { } } finally { if (sheet != null) { System.Runtime.InteropServices.Marshal.ReleaseComObject(sheet); } } } finally { if (sheets != null) { System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets); } } } finally { if (workbook != null) { try { workbook.GetType().InvokeMember("Close", BindingFlags.Public | BindingFlags.InvokeMethod, null, workbook, null); } finally { System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook); } } } } finally { if (workbooks != null) { System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks); } } } finally { if (excelApp != null) { try { excelApp.GetType().InvokeMember("Quit", BindingFlags.Public | BindingFlags.InvokeMethod, null, excelApp, null); } finally { System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp); } } } } } }