PowerShell を使って、ExcelDataReader で Excel ファイルを読み込む

2020/04/18

経緯

お客さまからいただく Excel ファイルを、あるフォーマットにするということを、手作業でちまちまやるのをやめたいので、ちょっとスクリプト書いてます

ググったら、「読み込むだけなら ExcelDataReader が速くていいぞー」「ExcelDataReader は xlsx だけではなくて、xls も読めるぞー」的なことを書いていて、ちょっと触ってみたくなったのです

環境

  • Windows 10 Pro
  • PowerShell 5.1
  • ExcelDataReader 3.6.0
  • ExcelDataReader.DataSet 3.6.0

ライブラリのダウンロード

それぞれ、右メニューにある Download package から nuget パッケージをダウンロードして、拡張子を zip に変えて解凍後、DLL を取り出した

Excel ファイルの準備

サンプルで Excel ファイル (test.xlsx) を作りました

「商品」と「従業員」というシートを作って、それぞれ適当なデータを入れています

Excel データの読み込み

DLL 2 つ、Excel ファイル 1 つ、 PowerShell ファイルをすべて同じディレクトリに置きました

ココまでの状態

データを読み込むところまでコードを書いてみます

$ErrorActionPreference = 'Stop'

# カレントのパス
$currentPath = Split-Path -Parent $MyInvocation.MyCommand.Path

# DDL の読み込み
[void][Reflection.Assembly]::LoadFile((Join-Path $currentPath '.\ExcelDataReader.dll'))
[void][Reflection.Assembly]::LoadFile((Join-Path $currentPath '.\ExcelDataReader.DataSet.dll'))

try {
    # FileStream を開く
    $stream = [System.IO.File]::Open('.\test.xlsx', [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)

    # ExcelReader の生成 
    $reader = [ExcelDataReader.ExcelReaderFactory]::CreateReader($stream)

    # ExcelDataSetConfiguration 生成
    $config = [ExcelDataReader.ExcelDataSetConfiguration]::new()
    $config.UseColumnDataType = $true
    $config.ConfigureDataTable = {
        $conf = [ExcelDataReader.ExcelDataTableConfiguration]::new()
        $conf.UseHeaderRow = $true
        return $conf
    }

    # データの読み込み
    $data = [ExcelDataReader.ExcelDataReaderExtensions]::AsDataSet($reader, $config)
} catch {
    throw
} finally {
    # オブジェクトの解放
    if ($reader -is [ExcelDataReader.IExcelDataReader]) {
        $reader.Close()
        $reader.Dispose()
        $reader = $null
    }
    if ($stream -is [System.IO.FileStream]) {
        $stream.Close()
        $stream.Dispose()
        $stream = $null
    }
}

AsDataSet メソッドを使うところがちょっと大変でした... (C# の例は腐るほどあったんですがw)

ここまでで、 $data にデータを取得できていますので、データタイプを見てみます

DataSet で返ってきているのがわかります

中を雑にかくにんしてみます

# 雑に中を確認
$data.Tables | %{
    Write-Output ('SheetName: {0}' -f $_.TableName)
    Format-Table -InputObject $_.Rows
}

最後にオブジェクトを解放して終わります

# ExcelDataReader.DataSet は .NET 3.5 でコンパイルされているようで、System.Type に比較演算子が実装されていないので FullName で判断
if ($data.GetType().FullName -eq "System.Data.DataSet") {
    $data.Clear()
    $data.Dispose()
    $data = $null
}