Option Explicit
Option Base 1
'==================================================
' モジュール名: Mod_ImportFile
' 概要: CSVファイルのインポート機能を提供するモジュール
' 主な機能: ファイル取込、項目リスト処理、シート出力
'==================================================
'--------------------------------------------------
' 構造体:CSV項目とそのデータ
'--------------------------------------------------
Type typCsvItem
strItemName As String
arrStrValues() As String
End Type
'--------------------------------------------------
'プロシージャの概要:
'処理名:onClickImportFile
'概要:CSVファイル取込ボタン押下時のメイン処理。
'項目定義とCSVファイル内容を読み込み、shImportシートに出力する。
'--------------------------------------------------
Sub onClickImportFile()
On Error GoTo lblErr
Dim arrTypItems() As typCsvItem
Dim strCsvFolder As String
Dim strCsvFile As String
Dim strFilePath As String
Dim strMsg As String
' フォルダパス・ファイル名を取得
Call getCsvPath(strCsvFolder, strCsvFile)
' フォルダ存在確認
If Not blnExistsFolder(strCsvFolder) Then Exit Sub
'ファイル名チェック
'実装中
' フルパス生成
strFilePath = strCsvFolder & strCsvFile
' ファイル存在確認
If Not blnExistsFile(strFilePath) Then Exit Sub
' 項目リストの読込
If blnTypGetItemList(arrTypItems) = False Then Exit Sub
' CSVデータの読込
If blnLoadCsvData(strFilePath, arrTypItems) = False Then Exit Sub
' shImportへの出力
If blnWriteImportSheet(arrTypItems) = False Then Exit Sub
' 処理完了通知
strMsg = "ファイルの取込が完了しました。"
MsgBox strMsg, vbInformation, "onClickImportFile : 完了"
Exit Sub
lblErr:
MsgBox "ファイル取込処理中にエラーが発生しました。" & vbCrLf & _
"エラー番号: " & Err.Number & vbCrLf & _
"内容: " & Err.Description, vbExclamation, "onClickImportFile"
End Sub
'--------------------------------------------------
'プロシージャの概要:
'処理名:blnLoadCsvData
'概要:指定されたCSVファイルを開き、構造体配列に対応する項目のデータを一括取得して格納する
'[引数1]:strPath:読み込むCSVファイルのフルパス
'[引数2]:arrItems:読み込んだデータを格納する構造体配列(項目名に一致する列の値)
'[戻り値]:Boolean:正常終了時 True、エラー発生時 False
'--------------------------------------------------
Private Function blnLoadCsvData(ByVal strPath As String, ByRef arrItems() As typCsvItem) As Boolean
Dim wbCsv As Workbook ' 読み込むCSVファイルのワークブック
Dim wsCsv As Worksheet ' CSVファイル内のワークシート(1枚目)
Dim lngCol As Long ' 列ループ用
Dim lngRow As Long ' 行ループ用
Dim lngLastCol As Long ' CSV内の最終列番号
Dim lngItemIndex As Long ' 構造体配列ループ用
Dim strItemName As String ' 構造体内の項目名
Dim strHeader As String ' CSVのヘッダー項目名(10行目)
Dim strErrMsg As String ' エラーメッセージ格納用文字列
Dim varColumnData As Variant ' 列データ一括取得用配列
' エラーハンドリング開始
On Error GoTo lblErr
' CSVファイルを読み取り専用で開く
Set wbCsv = Workbooks.Open(Filename:=strPath, ReadOnly:=True)
Set wsCsv = wbCsv.Worksheets(1)
With wsCsv
' 最終列番号の取得(10行目の最右列)
lngLastCol = .Cells(ROW_CSV_HEADER, .Columns.Count).End(xlToLeft).Column
' 構造体配列の各項目についてデータを読み込む
For lngItemIndex = LBound(arrItems) To UBound(arrItems)
' 対象項目名を取得
strItemName = arrItems(lngItemIndex).strItemName
For lngCol = 1 To lngLastCol
' CSVヘッダーから項目名を取得
strHeader = .Cells(ROW_CSV_HEADER, lngCol).Value
' 一致しない列はスキップ
If strHeader <> strItemName Then GoTo SkipColumn
' 対応列のデータを一括取得
varColumnData = .Range(.Cells(ROW_CSV_START, lngCol), _
.Cells(ROW_CSV_START + NUM_CSV_ROWS - 1, lngCol)).Value
' 値格納用の配列を初期化
ReDim arrItems(lngItemIndex).arrStrValues(1 To NUM_CSV_ROWS)
' 取得した列データを構造体に格納
For lngRow = 1 To NUM_CSV_ROWS
arrItems(lngItemIndex).arrStrValues(lngRow) = varColumnData(lngRow, 1)
Next lngRow
' 対応列が見つかったので次の項目へ
Exit For
SkipColumn:
Next lngCol
Next lngItemIndex
End With
' CSVファイルを保存せずに閉じる
wbCsv.Close SaveChanges:=False
blnLoadCsvData = True
Exit Function
lblErr:
' エラー発生時の処理
If Err.Number <> 0 Then
strErrMsg = "CSV読込処理中にエラーが発生しました。" & vbCrLf & _
"内容: " & Err.Description
Else
strErrMsg = "予期せぬ理由によりCSV読込処理が中断されました。"
End If
MsgBox strErrMsg, vbExclamation, "blnLoadCsvData"
If Not wbCsv Is Nothing Then wbCsv.Close SaveChanges:=False
blnLoadCsvData = False
End Function
'--------------------------------------------------
'プロシージャの概要:
'処理名:blnTypGetItemList
'概要:shItemsシートの項目名一覧を構造体配列に格納して返却(エラー時はFalse)
'[引数1]:arrTypItems:読み込んだ項目名を格納する構造体配列
'[戻り値]:Boolean: 正常終了時はTrue、エラー時はFalse
'--------------------------------------------------
Private Function blnTypGetItemList(ByRef arrTypItems() As typCsvItem) As Boolean
Dim lngLastRow As Long ' 項目列の最終行番号
Dim lngItemCount As Long ' 項目数
Dim lngIndex As Long ' ループカウンタ
Dim lngRow As Long ' セルの行番号
Dim strItemName As String ' セルから読み取った項目名
Dim strErrMsg As String ' エラーメッセージ格納用文字列
On Error GoTo lblErr
' 項目列(B列)最終行を取得
lngLastRow = shItems.Cells(shItems.Rows.Count, COL_shITM_NAME).End(xlUp).Row
' 項目数を算出
lngItemCount = lngLastRow - ROW_shITM_START + 1
' 項目が存在しない場合はエラーとして処理終了
If lngItemCount <= 0 Then
strErrMsg = "項目リストが空であるため処理を続行できません。"
GoTo lblErr
End If
' 構造体配列を初期化
ReDim arrTypItems(1 To lngItemCount)
' 項目名を構造体に格納
For lngIndex = 1 To lngItemCount
lngRow = ROW_shITM_START + lngIndex - 1 ' 対象セルの行番号を算出
strItemName = shItems.Cells(lngRow, COL_shITM_NAME).Value ' セルから項目名を取得
arrTypItems(lngIndex).strItemName = strItemName ' 構造体に格納
Next lngIndex
blnTypGetItemList = True
Exit Function
lblErr:
If Err.Number <> 0 Then
strErrMsg = "項目リストの読込中にエラーが発生しました。" & vbCrLf & _
"内容: " & Err.Description
End If
MsgBox strErrMsg, vbExclamation, "blnTypGetItemList"
blnTypGetItemList = False
End Function
'--------------------------------------------------
'プロシージャの概要:
'処理名:blnWriteImportSheet
'概要:構造体配列に格納された項目名およびCSVデータをshImportシートに出力する。
' 各行の右端にはSUM関数による合計列も追加する。
'[引数1]:arrTypItems:出力対象となる項目名と値を持つ構造体配列
'[戻り値]:Boolean:正常終了時 True、エラー発生時 False
'--------------------------------------------------
Function blnWriteImportSheet(ByRef arrTypItems() As typCsvItem) As Boolean
Dim lngRow As Long ' 行ループ用カウンタ
Dim lngCol As Long ' 列インデックス
Dim lngItemIndex As Long ' 構造体配列インデックス
Dim lngSumCol As Long ' 合計列の列番号
Dim arrOutput() As Variant ' 出力用二次元配列
Dim arrHeader() As Variant ' ヘッダー出力用一次元配列
Dim arrCol() As String ' 一時列データ配列
Dim rngHeaderStart As Range ' ヘッダー出力開始セル
Dim rngHeaderEnd As Range ' ヘッダー出力終了セル
Dim rngDataStart As Range ' データ出力開始セル
Dim rngDataEnd As Range ' データ出力終了セル
Dim lngCurrentRow As Long ' 現在処理中の行番号
Dim strStartCol As String ' 合計範囲の開始列(列文字)
Dim strEndCol As String ' 合計範囲の終了列(列文字)
Dim strFormula As String ' 合計用数式文字列
On Error GoTo lblErr
With shImport
' インポートシート全体を初期化(既存データを削除)
.Cells.ClearContents
'--------------------------
' ヘッダー出力
'--------------------------
' 構造体配列からヘッダー出力用の配列を作成
ReDim arrHeader(1 To 1, 1 To UBound(arrTypItems))
For lngItemIndex = LBound(arrTypItems) To UBound(arrTypItems)
' 各構造体に格納された項目名をヘッダー用配列に格納
arrHeader(1, lngItemIndex) = arrTypItems(lngItemIndex).strItemName
Next
' ヘッダー出力範囲を変数に格納し、一括出力
' ヘッダー行の出力開始セル(左端)を設定
Set rngHeaderStart = .Cells(ROW_shIMP_HEADER, ROW_shIMP_VALSTART)
' ヘッダー行の出力終了セル(右端)を設定
Set rngHeaderEnd = .Cells(ROW_shIMP_HEADER, ROW_shIMP_VALSTART + UBound(arrTypItems) - 1)
' 構造体から作成した項目名をヘッダー行に一括出力
.Range(rngHeaderStart, rngHeaderEnd).Value = arrHeader
'--------------------------
' 値出力
'--------------------------
' 出力用のデータ配列を初期化(CSV行数×項目数)
ReDim arrOutput(1 To NUM_CSV_ROWS, 1 To UBound(arrTypItems))
' 各項目(列)ごとにCSVデータをデータ配列に転記
For lngItemIndex = LBound(arrTypItems) To UBound(arrTypItems)
' 構造体から対象項目の全行分の値を配列として取得
arrCol = arrTypItems(lngItemIndex).arrStrValues
For lngRow = 1 To NUM_CSV_ROWS
arrOutput(lngRow, lngItemIndex) = arrCol(lngRow)
Next
Next
' データ出力範囲を変数に格納し、一括出力
Set rngDataStart = .Cells(ROW_shIMP_VALSTART, ROW_shIMP_VALSTART)
' データ出力の右下セル(最終行・最終列)を設定
Set rngDataEnd = .Cells(ROW_shIMP_VALSTART + NUM_CSV_ROWS - 1, ROW_shIMP_VALSTART + UBound(arrTypItems) - 1)
' 構造体配列から生成したCSVデータ本体を一括でインポートシートに出力
.Range(rngDataStart, rngDataEnd).Value = arrOutput
'--------------------------
' 合計出力
'--------------------------
' 合計列の列番号を設定(データ列の直後)
lngSumCol = ROW_shIMP_VALSTART + UBound(arrTypItems)
' 合計列のヘッダーに「合計」を出力
.Cells(ROW_shIMP_HEADER, lngSumCol).Value = "合計"
' 各行にSUM関数を設定(A1形式で列名を使用)
For lngRow = 1 To NUM_CSV_ROWS
' 現在処理中の行番号
lngCurrentRow = ROW_shIMP_VALSTART + lngRow - 1
' 列番号を列文字に変換
strStartCol = strGetColumnLetter(ROW_shIMP_VALSTART)
strEndCol = strGetColumnLetter(lngSumCol - 1)
' A1形式での合計範囲の作成
strFormula = "=SUM(" & _
strStartCol & lngCurrentRow _
& ":" & strEndCol & lngCurrentRow & ")"
' セルに数式を設定
.Cells(lngCurrentRow, lngSumCol).Formula = strFormula
Next
End With
' 正常終了時は True を返す
blnWriteImportSheet = True
Exit Function
lblErr:
' エラー発生時のメッセージ表示
MsgBox "インポートシートへの出力中にエラーが発生しました。" & vbCrLf & _
"内容: " & Err.Description, vbExclamation, "blnWriteImportSheet"
blnWriteImportSheet = False
End Function
コメント