あるSEのつぶやき・改

ITやシステム開発などの技術に関する話題を、取り上げたりしています。

PowerShell, UTF-8のCSVファイルを1行ずつ読み込みExcelにインポートする

PowerShell の用途として多いと思われるのが、CSV ファイルを読み込んで処理を行うことです。バッチの定番ですからね。

ただ、UTF-8 の CSV ファイルを1行ずつ読み込んで Excel に取り込むとなると .NET Framework の機能を利用することになります。

この記事では、.NET Framework の Microsoft.VisualBasic.FileIO.TextFieldParser クラスを利用したサンプルスクリプトを提示します。

なお、TextFieldParser を利用すると、CSV ファイルを簡単に扱うことができます。

まず、以下のようなデータが UTF-8 で users.csv で保存されているとします。

"001","山田太郎"
"002","佐藤花子"
"003","田中次郎"

サンプルスクリプトを実行した結果は、以下のようになります。

f:id:fnyablog:20180908191935j:plain

サンプルスクリプトは以下のようになります。

#
# UTF-8のCSVファイルをExcelにインポートするスクリプト
#


# アセンブリをロードする
[void][reflection.assembly]::LoadWithPartialName("Microsoft.VisualBasic")

# スクリプトの親フォルダのパスを取得する
$path = Split-Path $MyInvocation.MyCommand.Path -Parent

# CSV ファイルのパスを作成する
$csvPath = Join-Path $path "users.csv"

# Excel の保存先のパスを作成する
$xlsPath = Join-Path $path "users.xlsx"

# CSV ファイルのエンコーディングを指定する
$enc = [System.Text.Encoding]::UTF8

# パーサーで CSV ファイルを開く
$parser = New-Object -TypeName Microsoft.VisualBasic.FileIO.TextFieldParser $csvPath, $enc

# CSV ファイルが可変長であることを指定する
$parser.TextFieldType = [Microsoft.VisualBasic.FileIO.FieldType]::Delimited

# CSV ファイルがカンマ区切りであることを指定する
$parser.SetDelimiters(","); 

# CSV ファイルの区切り文字がダブルクォーテーションであることを明示する
$parser.HasFieldsEnclosedInQuotes = $true

# Excel を起動する
$xls = New-Object -ComObject Excel.Application

# WorkBook を追加する
$wb = $xls.WorkBooks.Add()

# シートを選択する
$ws = $wb.WorkSheets.Item("Sheet1")

# 変数を初期化する
$i = 1
$j = 1

# 最終レコードまで読み込む
While($parser.EndOfData -eq $false) {
  # カンマでテキストを区切り配列に格納する
  $fields = $parser.ReadFields()

  # 配列を順番に処理する
  foreach ($field in $fields) {

    # セルの書式を「文字列」にする
    $ws.Cells.Item($i, $j).NumberFormat = "@"

   # セルに値を設定する
   $ws.Cells.Item($i, $j).Value = $field

   # 列を1つ進める
   $j++
  }

  # 行を1つ進める
  $i++

  # 変数初期化
  $j = 1
}

# ファイルが既存の場合警告メッセージを表示しないようにする
$xls.DisplayAlerts = $false

# Excel ファイルを保存する
$wb.SaveAs([ref]$xlsPath.ToString())
#$wb.SaveAs([ref]$xlsPath.ToString(), -4143) # xls形式の時はこちらを使用する

# 警告メッセージの表示を元に戻す
$xls.DisplayAlerts = $true

# WorkBook を閉じる
$wb.Close()

# Excel を終了する
$xls.Quit()

# CSV ファイルを閉じる
$parser.Close()

# COM 参照を解放する
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($ws)
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($wb)
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($xls)