固定長形式テキストデータの読み込み

項目区切りはなく、固定バイト位置で項目を見分ける形式のテキストファイルです。
COBOL言語で作成されたシステムで取り扱うことが多い形式です。  私もWindows環境以前は、COBOL言語でのシステム開発を行なっていたのですが、COBOL言語でのデータファイルの取り扱いは「固定長形式」がほとんどです。
CSV形式テキスト(カンマ区切り、*.csv)などの概念がないので不便に見えますが、レコード上を項目定義してしまうので読み込んだ時点で項目ごとに個別の変数で扱える利便性があります。 ここではCOBOL言語の説明をするわけではありませんが、そのインタフェースとなる固定長形式ファイルを読み込んでシート上に展開するというサンプルです。
サンプルは、「固定長形式テキストデータの書き出し」で書き出しているものと同じですから、セットで確認すると良いでしょう。



まずは、改行付きの固定長形式テキストデータを読み込んでみます。
読み込みデータは、「固定長形式テキストデータの書き出し」で作成した、このようなデータです。
固定長形式テキストデータ(改行付き)
(画像をクリックすると、このサンプルがダウンロードできます)





固定長形式ファイルの内容は以下のようにしています。
No. 項目名 タイプ 桁数 COBOL言語での編集
1 コード 文字 5  PIC X(05)
2 メーカー 文字 10  PIC X(10)
3 品名 文字 15  PIC X(15)
4 数量 符号無数値 4  PIC 9(04)
5 単価 符号無数値 6  PIC 9(06)
6 金額 符号無数値 8  PIC 9(08)
48  

「桁数」は実際には「バイト数」になります。レコード当たり48バイト(改行付きはプラス2バイト)で読み込んで、レコードを各項目に切り分けるわけです。





固定長形式テキストデータを読み込むマクロの起動
サンプルブックには、このページの2つのサンプルコードのプロシージャを収容してありますが、改行付きの場合は「READ_FixLngFile1」を起動させて下さい。読み込みデータファイルは同じフォルダにある「SAMPLE1.dat」と固定してあります。





固定長形式テキストデータを読み込んだところ
このような結果になるはずです。少ない件数なので一瞬で終了するはずです。





こちらのサンプルコードはこんな形にしてみました。

'***************************************************************************************************
'   固定長形式テキストファイルを読み込むサンプル(改行あり)          Module1(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'   [参照設定]
'   ・Microsoft Scripting Runtime
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'03/07/25(1.00)新規作成
'03/12/04(1.01)初回修正
'20/02/26(1.10)*.xlsm化、他
'***************************************************************************************************
Option Explicit
'===================================================================================================
Private Const g_cnsTitle As String = "固定長形式テキストファイル読み込み"
Private Const g_cnsFilename As String = "SAMPLE1.dat"

'***************************************************************************************************
'   ■■■ ワークシート側からの呼び出し処理 ■■■
'***************************************************************************************************
'* 処理名 :READ_FixLngFile1
'* 機能  :固定長形式テキストファイルを読み込むサンプル(改行あり)
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月25日
'* 作成者 :井上 治
'* 更新日 :2020年02月26日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:サンプルなのでエラー処理は行なっていません
'***************************************************************************************************
Sub READ_FixLngFile1()
    '-----------------------------------------------------------------------------------------------
    Dim objFso As FileSystemObject                              ' FileSystemObject
    Dim objTs As TextStream                                     ' TextStream
    Dim lngRow As Long                                          ' 収容するセルの行
    Dim lngRec As Long                                          ' レコード件数カウンタ
    Dim strRec As String                                        ' レコードを収容する変数
    Dim strFileName As String                                   ' OPENするファイル名(フルパス)
    '-----------------------------------------------------------------
    Set objFso = New FileSystemObject
    ' フルパスファイル名の編集
    strFileName = objFso.BuildPath(ThisWorkbook.Path, g_cnsFilename)
    ' 指定ファイルをOPEN(入力モード)
    Set objTs = objFso.OpenTextFile(Filename:=strFileName, IOMode:=ForReading)
    Set objFso = Nothing
    ' 2行目から開始
    Rows("2:" & Rows.Count).ClearContents
    lngRow = 2
    '-----------------------------------------------------------------
    ' ファイルのEOFまで繰り返す
    Do Until objTs.AtEndOfStream
        ' レコード件数カウンタの加算
        lngRec = lngRec + 1
        Application.StatusBar = "読み込み中です....(" & lngRec & "レコード目)"
        ' 改行までをレコードとして読み込む
        strRec = StrConv(objTs.ReadLine, vbFromUnicode)
        ' 1レコード分のセルへのセット
        Call GP_EditFixLngRec(strRec, lngRow)
        ' 行を加算
        lngRow = lngRow + 1
    Loop
    '-----------------------------------------------------------------
    ' 指定ファイルをCLOSE
    objTs.Close
    Set objTs = Nothing
    Application.StatusBar = False
    ' 終了の表示
    MsgBox "ファイル読み込みが完了しました。" & vbCr & _
        "レコード件数=" & lngRec & "件", vbInformation, g_cnsTitle
End Sub

'***************************************************************************************************
'   ■■■ サブ処理(Private) ■■■
'***************************************************************************************************
'* 処理名 :GP_EditFixLngRec
'* 機能  :CSV形式テキストの1レコードのセルへの転記
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :Arg1 = 読み込みレコード内容(String)
'*      Arg2 = 収容するセルの行(Long)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月25日
'* 作成者 :井上 治
'* 更新日 :2020年02月26日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Private Sub GP_EditFixLngRec(ByVal strRec As String, ByVal lngRow As Long)
    '-----------------------------------------------------------------------------------------------
    ' A列(コード)は5バイトの文字列処理
    Cells(lngRow, 1).Value = FP_GetFldFromRecS(strRec, 1, 5)
    ' B列(メーカー)は10バイトの文字列処理
    Cells(lngRow, 2).Value = FP_GetFldFromRecS(strRec, 6, 10)
    ' C列(品名)は15バイトの文字列処理
    Cells(lngRow, 3).Value = FP_GetFldFromRecS(strRec, 16, 15)
    ' D列(数量)は4バイトの数値処理
    Cells(lngRow, 4).Value = FP_GetFldFromRecN(strRec, 31, 4)
    ' E列(単価)は6バイトの数値処理
    Cells(lngRow, 5).Value = FP_GetFldFromRecN(strRec, 35, 6)
    ' F列(金額)は8バイトの数値処理
    Cells(lngRow, 6).Value = FP_GetFldFromRecN(strRec, 41, 8)
End Sub

'***************************************************************************************************
'* 処理名 :FP_GetFldFromRecS
'* 機能  :固定長データから指定バイト数を切り出す(文字列処理)
'---------------------------------------------------------------------------------------------------
'* 返り値 :取得した文字列(String)
'* 引数  :Arg1 = 読み込みレコード内容(String)
'*      Arg2 = 開始バイト位置(Long)
'*      Arg3 = 項目バイト数(Long)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月25日
'* 作成者 :井上 治
'* 更新日 :2020年02月26日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Private Function FP_GetFldFromRecS(ByVal strRec As String, _
                                   ByVal lngStrPos As Long, _
                                   ByVal lngLngs As Long) As String
    '-----------------------------------------------------------------------------------------------
    FP_GetFldFromRecS = Trim(StrConv(MidB(strRec, lngStrPos, lngLngs), vbUnicode))
End Function

'***************************************************************************************************
'* 処理名 :FP_GetFldFromRecN
'* 機能  :固定長データから指定バイト数を切り出す(整数処理)
'---------------------------------------------------------------------------------------------------
'* 返り値 :取得した数値(Currency)
'* 引数  :Arg1 = 読み込みレコード内容(String)
'*      Arg2 = 開始バイト位置(Long)
'*      Arg3 = 項目バイト数(Long)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月25日
'* 作成者 :井上 治
'* 更新日 :2020年02月26日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Private Function FP_GetFldFromRecN(ByVal strRec As String, _
                                   ByVal lngStrPos As Long, _
                                   ByVal lngLngs As Long) As Currency
    '-----------------------------------------------------------------------------------------------
    Dim strRec2 As String                                           ' 切り出した文字列
    strRec2 = StrConv(MidB(strRec, lngStrPos, lngLngs), vbUnicode)
    FP_GetFldFromRecN = CCur(strRec2)
End Function

'----------------------------------------<< End of Source >>----------------------------------------
FSO(FileSystemObject)を使用しているので、読み込みの基本部分は「テキストデータの読み込み」の後半のサンプルコードの方法と同じで、そのレコードの内容の分解には一旦StrConv関数でAsciiコードに戻してMidB関数でバイト位置で分解させています。
「メーカー」や「品名」などの全角半角混在項目が含まれている場合、文字数換算では一定でないため単にMid関数では項目を正しく切り出せないので、このような方法を採るわけです。
GP_EditFixLngRecプロシージャ及び、そこから呼び出されている編集用サブプロシージャを調整してやれば、他のレイアウトの固定長形式テキストデータでも対応できると思います。

次は、改行なしの固定長形式テキストデータを読み込みます。
読み込みデータは、上記改行付きと同じ内容で、改行コードが付加されていないものです。
COBOL言語などで出力される固定長形式データとは本来このようなものです。
固定長形式テキストデータ(改行なし)
この画面だと、レコードの「切れ目」がよく分かりませんが、
固定長形式テキストデータ(改行なし)
このようにテキストエディタ上で1行のバイト数を48バイトに調整すると、改行コードがないだけでそれ以外はこのページの最初のデータと同じであることが分かります。





固定長形式テキストデータを読み込むマクロの起動
サンプルブックには、このページの2つのサンプルコードのプロシージャを収容してありますが、改行なしの場合は「READ_FixLngFile2」を起動させて下さい。読み込みデータファイルは同じフォルダにある「SAMPLE2.dat」と固定してあります。





固定長形式テキストデータを読み込んだところ
このような結果になるはずです。少ない件数なので一瞬で終了するはずです。





こちらのサンプルコードはこんな形にしてみました。

'***************************************************************************************************
'   固定長形式テキストファイルを読み込むサンプル(改行なし)          Module2(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'   [参照設定]
'   ・Microsoft Scripting Runtime
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'03/07/25(1.00)新規作成
'03/12/04(1.01)初回修正
'20/02/26(1.10)*.xlsm化、他
'***************************************************************************************************
Option Explicit
'===================================================================================================
Private Const g_cnsTitle As String = "固定長形式テキストファイル読み込み"
Private Const g_cnsFilename As String = "SAMPLE2.dat"
Private Const g_cnsLngs As Long = 48                        ' レコード長
'---------------------------------------------------------------------------------------------------
' レコードの項目定義(ユーザー定義)
Private Type g_typRec
    CODE As String * 5                                      ' コード
    MAKER As String * 10                                    ' メーカー
    HINMEI As String * 15                                   ' 品名
    SURYO As String * 4                                     ' 数量
    TANKA As String * 6                                     ' 単価
    KINGAKU As String * 8                                   ' 金額
'    CRLF As String * 2                                      ' 改行コード分のダミー項目
End Type

'***************************************************************************************************
'   ■■■ ワークシート側からの呼び出し処理 ■■■
'***************************************************************************************************
'* 処理名 :READ_FixLngFile2
'* 機能  :固定長形式テキストファイルを読み込むサンプル(改行なし)
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2003年07月25日
'* 作成者 :井上 治
'* 更新日 :2020年02月26日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:サンプルなのでエラー処理は行なっていません
'***************************************************************************************************
Sub READ_FixLngFile2()
    '-----------------------------------------------------------------------------------------------
    Dim objFso As FileSystemObject                              ' FileSystemObject
    Dim strFileName As String                                   ' ファイル名
    Dim intFF As Integer                                        ' FreeFile値
    Dim lngRow As Long                                          ' 収容するセルの行
    Dim lngRec As Long                                          ' レコード件数カウンタ
    Dim lngLof As Long                                          ' LOF値
    Dim lngPos As Long                                          ' 読み込み位置
    Dim strRec As String                                        ' レコードを収容する変数
    Dim tmpRec As g_typRec                                      ' レコード定義
    '-----------------------------------------------------------------
    Set objFso = New FileSystemObject
    ' フルパスファイル名の編集
    strFileName = objFso.BuildPath(ThisWorkbook.Path, g_cnsFilename)
    Set objFso = Nothing
    ' 指定ファイルをOPEN(バイナリモード)
    intFF = FreeFile
    Open strFileName For Binary As #intFF
    lngLof = LOF(intFF)             ' LOF値(ファイルサイズ)取得
    lngPos = 1                      ' 読み込み位置
    ' 2行目から開始
    Rows("2:" & Rows.Count).ClearContents
    lngRow = 2
    '-----------------------------------------------------------------
    ' ファイルのEOFまで繰り返す
    Do Until lngPos > lngLof
        ' レコード件数カウンタの加算
        lngRec = lngRec + 1
        Application.StatusBar = "読み込み中です....(" & lngRec & "レコード目)"
        ' レコードの読み込み
        Get #intFF, lngPos, tmpRec
        ' 1レコード分のセルへのセット
        '-----------------------------------------
        ' A列(コード)は5バイトの文字列処理
        Cells(lngRow, 1).Value = Trim(tmpRec.CODE)
        ' B列(メーカー)は10バイトの文字列処理
        Cells(lngRow, 2).Value = Trim(tmpRec.MAKER)
        ' C列(品名)は15バイトの文字列処理
        Cells(lngRow, 3).Value = Trim(tmpRec.HINMEI)
        ' D列(数量)は4バイトの数値処理
        Cells(lngRow, 4).Value = CCur(tmpRec.SURYO)
        ' E列(単価)は6バイトの数値処理
        Cells(lngRow, 5).Value = CCur(tmpRec.TANKA)
        ' F列(金額)は8バイトの数値処理
        Cells(lngRow, 6).Value = CCur(tmpRec.KINGAKU)
        '-----------------------------------------
        ' 読み込み位置に1レコード分を加算
        lngPos = lngPos + g_cnsLngs
        ' 行を加算
        lngRow = lngRow + 1
    Loop
    '-----------------------------------------------------------------
    ' 指定ファイルをCLOSE
    Close #intFF
    Application.StatusBar = False
    ' 終了の表示
    MsgBox "ファイル読み込みが完了しました。" & vbCr & _
        "レコード件数=" & lngRec & "件", vbInformation, g_cnsTitle
End Sub

'----------------------------------------<< End of Source >>----------------------------------------
こちらはFSO(FileSystemObject)ではなく、バイナリモードでOpenさせて、Getステートメントで処理しています。 Getステートメントでは、読み込み開始位置やバイト数を指定できるのでこのような処理には向いているわけです。(ファイルの先頭から順に読み込む場合は、開始位置(lngPOS)は省略しても構いません。)
読み込みに使う変数のタイプには、先頭で宣言しておいたユーザー定義型(Typeステートメント)を使用することで、セルへのセットも単純な項目転記で利用できます。





こちらの方法で改行付きの固定長形式テキストファイルを読み込むことができます。 この場合は、ユーザー定義の宣言の最後のコメントにしてある「CRLF」を有効にして1レコードを50バイト(Const cnsLNGS = 50)にするだけです。





さて、こちらのページでは、数値項目は符号なしの整数のみとしてありますが、COBOL言語では「符号」に桁を占有させないデータ形式を採るのでこれは直接Visual Basicで使用するデータ型に転記させることができません。 この件については、「固定長形式テキストデータの書き出し」の最後で説明しているので、そちらを参考にしてみて下さい。