ClosedXMLでExcelをシート毎に辞書変数に格納したい Dictionary(Of String, DataTable)

対象のExcelファイルが重いことと拡張性(主にヘッダーの有無の処理を綺麗にするため)の観点から
Excelモダンやワークブックアクティビティではなく
InvokeCodeアクティビティで実装したいと考えております。

上記処理を実行すると以下エラーが発生します。
エラー原因や改善方法をご教示いただけないでしょうか。
また、上記処理に関してより良い方法があれば、そちらもご教示いただけますと幸いです。

image
err_log.txt (2.5 KB)
ConvExcel2DicDt.xaml (9.4 KB)

こんにちは

dtTempがnullのまま列追加しているからかと思います。インスタンスを生成してみてください。

いつもお世話になっております。
ご回答ありがとうございます。
dtTmpの宣言時にインスタンスを生成しましたが、
同様の内容でエラーになりました。
他に考えられることはありますでしょうか。

Dim wb = New ClosedXML.Excel.XLWorkbook(i_sExcelPath)
Dim ws As ClosedXML.Excel.IXLWorksheet
Dim iLastRow As Integer
Dim iLastCol As Integer
Dim drRow As DataRow
Dim dtTmp As New DataTable
o_dicDt = New Dictionary(Of String, DataTable)

'シート分ループ
For iSheetCnt As Integer = 0 To wb.Worksheets.Count

  ws = wb.Worksheets(iSheetCnt)
  iLastRow = ws.LastRowUsed.RowNumber
  iLastCol = ws.LastColumnUsed.ColumnNumber
  
  '一時Datatableに列追加※i_isHeaderがTrueの場合は先頭行をカラム名にする
  If i_isHeader Then
  	For iColCnt As Integer = 1 To iLastCol
  		dtTmp.Columns.Add(ws.Cell(1, iColCnt).Value.ToString)
  	Next
  Else
  	For iColCnt As Integer = 1 To iLastCol
  		dtTmp.Columns.Add("Column" + iColCnt.ToString)
  	Next
  End If
  
  'Excelの使用行分ループ
  For iRowCnt As Integer = 2 To iLastRow - 1
  	drRow = dtTmp.NewRow
  	'Excelの使用列分ループ
  	For iColCnt As Integer = 1 To iLastCol
  		drRow(iColCnt - 1) = ws.Cell(iRowCnt, iColCnt).Value
  	Next
  	dtTmp.Rows.Add(drRow)
  Next
  
  'Key:シート名、Value:データテーブル
  o_dicDt(ws.Name) = dtTmp

Next

上記では生成していなようですが?

Dim dtTmp As New DataTable = New DataTable()

とする必要がありますが、このロジックですと各シートのループ内で初期化する必要がありそうなので

最初のForの直後に

dtTemp = New DataTable()

としてみてください

宣言時はそのままでループ内でインスタンスを生成するようにしましたが、
まだ同じエラーが発生してしまいます。
Excelのシート毎に列数が違うのでループ内で都度Datatableをリセットするようにしましたが、
まだ駄目なようです。。。

Try
Dim wb = New ClosedXML.Excel.XLWorkbook(i_sExcelPath)
Dim ws As ClosedXML.Excel.IXLWorksheet
Dim iLastRow As Integer
Dim iLastCol As Integer
Dim drRow As DataRow
Dim dtTmp As DataTable
o_dicDt = New Dictionary(Of String, DataTable)

'シート分ループ
For iSheetCnt As Integer = 0 To wb.Worksheets.Count

  ws = wb.Worksheets(iSheetCnt)
  iLastRow = ws.LastRowUsed.RowNumber
  iLastCol = ws.LastColumnUsed.ColumnNumber
  dtTmp = New DataTable()
  
  '一時Datatableに列追加※i_isHeaderがTrueの場合は先頭行をカラム名にする
  If i_isHeader Then
  	For iColCnt As Integer = 1 To iLastCol
  		dtTmp.Columns.Add(ws.Cell(1, iColCnt).Value.ToString)
  	Next
  Else
  	For iColCnt As Integer = 1 To iLastCol
  		dtTmp.Columns.Add("Column" + iColCnt.ToString)
  	Next
  End If
  
  'Excelの使用行分ループ
  For iRowCnt As Integer = 2 To iLastRow - 1
  	drRow = dtTmp.NewRow
  	'Excelの使用列分ループ
  	For iColCnt As Integer = 1 To iLastCol
  		drRow(iColCnt - 1) = ws.Cell(iRowCnt, iColCnt).Value
  	Next
  	dtTmp.Rows.Add(drRow)
  Next
  
  'Key:シート名、Value:データテーブル
  o_dicDt(ws.Name) = dtTmp.Copy
  
  'シートによってカラムが違う可能性を考慮してリセット
  dtTmp.Reset

Next

Catch ex As Exception
Throw
End Try

シート分ループの終了値が正しくなかったみたいです。
ありがとうございました。

For iSheetCnt As Integer = 0 To wb.Worksheets.Count - 1

参考ですがInvokeCodeでのエラーはその内容から判断する必要があります(以下画像の矢印の部分で判断します)
おそらく後者のエラーは、最初のエラーとは異なるものと思います。

2 Likes

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.