F#からExcelファイル(BIFF8)の読み込み
Bravo2.Excel
http://www.vector.co.jp/soft/winnt/prog/se399617.html
というライブラリを使わせて頂きました。
何度もシート名を指定したくないので一度Selectしたらシートオブジェクトをキャッシュするようにしました。
また、C# のような using ステートメントが使えるかは試していませんが、念のために一応IDisposeを実装してます。
クラスを定義するのに結構時間が掛かり、簡単にはF#に慣れないものだなと感じます。
[使い方]
let xls = new ExcelReader(path) // 指定したシート名のA1の値を取得 if xls.Select(name) then xls.["A1"] |> printfn "A1=\"%s\"" // シート名を全て出力 xls.Sheets |> List.iter (fun a -> printfn "%s" a) xls.Close() </pre>
[ラッピングしたソースコード]
namespace Common open System open Bravo2.Excel type ExcelReader private(book, sheetNameList) = let mutable book : ExcelWorkBook = book let mutable sheet : ExcelWorkSheet = null let mutable sheetNameList = sheetNameList // Dispose member public this.Dispose () = if book <> null then book.Close() book <- null // Dispose interface IDisposable with override this.Dispose() = this.Dispose() // Close member public this.Close () = this.Dispose() /// シートが選択されているか取得 member public this.IsSelect with get () = sheet <> null /// シートの選択 member public this.Select (name : string) = let SET exp = if exp then sheet <- book.WorkSheets.Item(name) else sheet <- null exp sheetNameList |> List.exists (fun a -> a = name) |> SET /// シート名のListを取得 member public this.Sheets with get () = sheetNameList /// 指定したセルの値を取得 member public this.Item with get(address : string) = if this.IsSelect then sheet.Cells.Item(address).Value.ToString() else "" /// 指定したセルの値を取得 member public this.Item with get(sheetname : string, address : string) = if this.Select(sheetname) then sheet.Cells.Item(address).Value.ToString() else "" /// 指定したセルの値を取得 member public this.Item with get(row : int, col : int) = if this.IsSelect then sheet.Cells.Item(row, col).Value.ToString() else "" /// 指定したセルの値を取得 member public this.Item with get(sheetname : string, row : int, col : int) = if this.Select(sheetname) then sheet.Cells.Item(row, col).Value.ToString() else "" /// 指定したセルの値を取得 member public this.Range with get(address : string) = this.[address] /// 指定したセルの値を取得 member public this.Range with get(sheetname : string, address : string) = this.[sheetname , address] /// 指定したセルの値を取得 member public this.Range with get(row : int, col : int) = this.[row, col] /// 指定したセルの値を取得 member public this.Range with get(sheetname : string, row : int, col : int) = this.[sheetname, row, col] /// コンストラクタ public new (path) = let book = new ExcelWorkBook(path) book.Open() let sheetCount = book.WorkSheets.Count - 1 let list = [ for i = 0 to sheetCount do yield book.WorkSheets.Item(i).Name ] new ExcelReader(book, list) ;;
ちなみに、RangeとItem両方定義しているのは、Itemというのを使いたくないためです。
インデクサを提供するにはItemというプロパティでなければ出来なかったので、仕方なくRangeを新しく追加しています。
まあ、でもインデクサが主体になりそうなのであまり使わないかも・・・