固定長ファイル出力

 

このトピックでは、ABAPでUniCodeのシステムからSJISコードで固定長ファイル出力の方法を取り上げて説明します。

ABAPで文字コードの関係でSJISコードで固定長ファイルを出力するには少し工夫する必要があります。 タブ区切りやカンマ区切りのファイル出力にするほうがだんぜん楽ですが、ふるい既存システムへの連携で固定長ファイルにしなければならない場面がしばしばあります。

固定長ファイル出力の基本は、項目を固定バイト長に出力させることです。

問題点

以下の構造体をファイルに出力することを例とします。

TYPES:
  BEGIN OF typ_row,
    col1       TYPE C LENGTH 10,
    col2       TYPE C LENGTH 12,
  END   OF typ_row.

Unicodeシステムのため、co1に定義されたLENGTH=10はバイト数ではなく文字数ですので、SJISで出力されるバイト数は可変になります。 一番少ないのは、すべて半角文字の場合であり、出力バイト数が10×1半角文字1バイト=10バイトになります。 一番多いのは、すべて全角文字の場合であり、出力バイト数が10×1全角文字2バイト=20バイトになります。 col1の固定長出力は以下の2パターンに分けることができます。

  • 固定長>=20バイト
    col1の実際の出力バイト数が20を超えることがないため、カットする処理は必要がありません。
    但し、場合によって後ろにスペースを埋める必要があるため、col1の実際の出力バイト数を計算しなければなりません。
  • 固定長<20バイト、例えば:10バイト
    col1の実際の出力バイト数を計算して、10バイトに未満の場合のスペース埋め処理を実装するほか、10バイトを超えた場合の既存文字列のカット処理も実装しなければなりません。カットする際に、カットが全角文字の真ん中にならないように注意する必要があります。

対応方法

上記の課題を対応するポイントは以下になります。

  • 出力バイト数計算処理
    メソッドcl_abap_list_utilities⇒dynamic_output_lengthを利用して、出力バイト数を計算します。
    このメソッドは各文字が全角文字か半角文字かを判断して、全角文字なら2、半角文字なら1というアルゴリズムで出力長を計算しています。
  • 文字列カット処理
    メソッドcl_abap_list_utilities⇒read_from_display_layoutを利用して、文字列のカット処理を行います。
    このメソッドはカットされる箇所に全角文字が跨っている場合、文字化けにならないように該当全角文字を丸ごと捨てるようにしております。
  • スペース埋め処理 \\ CONCATENATE命令は文字列を連結する際に、デフォルトで文字列の後ろのスペースを削除するため、スペース埋め処理を行う時は、RESPECTING BLANKSオプションをつける必要があります。

固定バイト数で文字列を出力するサブルーチンのサンプルコードです。

*&---------------------------------------------------------------------*
*&      Form  F_OUTPUT_FIXED_BYTES
*&---------------------------------------------------------------------*
*       固定バイト数で文字列出力
*----------------------------------------------------------------------*
*      -->U_LEN   :  出力バイト長
*      -->U_FIELD : 入力値
*      -->C_STR   : 出力文字列
*----------------------------------------------------------------------*
FORM f_output_fixed_bytes
  USING
    u_len   TYPE i
    u_field
  CHANGING
    c_str.
  
  DATA:
    l_len       TYPE i,            "length
    l_cnt       TYPE i,
    l_rc         TYPE abap_list_repl_rc.

  CLEAR: c_str,
              l_cnt.
  
* byte数取得
  CALL METHOD cl_abap_list_utilities=>dynamic_output_length
    EXPORTING
      field = u_field
    RECEIVING
      len   = l_cnt.

* データ長が出力バイト長を超えた場合、出力バイト長で文字列をカット
  IF l_cnt > u_len.
    TRY.
        CALL METHOD cl_abap_list_utilities=>read_from_display_layout
          EXPORTING
            display_data   = u_field
            display_offset = 0
            display_length = u_len
          IMPORTING
            field          = c_str
            rc             = l_rc.

      CATCH cx_parameter_invalid_range .
    ENDTRY.

* byte数再取得 (カット箇所に全角文字が跨っているケースを考慮)
    CALL METHOD cl_abap_list_utilities=>dynamic_output_length
      EXPORTING
        field = c_str
      RECEIVING
        len   = l_cnt.

*   バイト数が足りない場合は、後ろにスペースを埋める
    WHILE l_cnt < u_len.
      CONCATENATE c_str
                  ' '
             INTO c_str
             RESPECTING BLANKS.
      l_cnt = l_cnt + 1.
    ENDWHILE.

  ENDIF.

ENDFORM.