改行コードがない可変長データを読み込む方法

[OS] ALL
[リリース] ALL
[キーワード] Base, DATA, INFILE, RECFM=N

[質問]

レコード内に各レコード項目の識別子はあるが、レコードの長さが記載されたフィールドがない、つまり「改行コードのない」可変長のテキストファイルがあります。
このようなファイルをSASで読み込むには、どのようにすればよいでしょうか。

[回答]

改行コードが存在しない可変長データの代表的なケースには、メインフレームから転送されてきたデータがあります。

ホスト上にて作成されたデータであり、かつメインフレームからの転送時にコード変換がされておらず、制御コードが付加されたままであれば、INFILEステートメントでRECFM=オプションに S370V、またはS370VBを指定することで読み込むことが可能です。

しかし、一般的なファイル転送ソフトウェアなどで転送された場合、可変長レコードの長さを示すRDWやBDWと呼ばれるフィールドは省略されるため、RECFM=オプションは利用できません。

各レコードの長さが格納されたフィールドがない場合、データのレコードフォーマットをRECFM=N (unbufferd)として扱い、次に記載するような方法を利用することで読み込むことが可能です。

  • レコードの各フィールドを全てフォーマット指定して、フォーマット入力する
  • レコードの各フィールドを、ポインタコントロールを利用してポインタ入力する
  • (識別レコードの組み合わせごとに長さが固定であれば)レコードの各フィールドの読み込み位置に、レコードの長さを付与する

可変長レコードの読み込みについては、次のページで「ホストからのEBCDICデータを読み込む方法」として紹介しています。

なお、一例として簡単なサンプルを記載します。

前提条件
  • 先頭1バイトのフラグで識別される長さの異なるデータがある
  • フラグで識別された各オブザベーション(レコード)の 組み合わせの長さは固定
    • 先頭1バイトが「1」の場合は200バイト
    • 先頭1バイトが「2」であれば1000バイト
  • 各オブザベーションには改行コードが存在しない
  • データはパック十進データを除き、ASCII変換済み

プログラム概要
  • 入力ファイル「VBREC1」をストリームレコード(1レコードのデータ)として読み込み、レコードレイアウトの異なる2つのデータを、それぞれ「REC1」「REC2」データセットとして分けて作成する。
  • 次のデータレコードの読み込み位置を変数「strec」に保持し、該当のレコードの開始位置を特定させる。

                                            /* 入力ファイル定義 */
FILENAME vbrec1 'C:¥test¥testvb.txt';
                                        /* 出力データセット定義 */
DATA WORK.rec1 WORK.rec2;
    /* 先頭からの位置を記録した変数をRETAINステートメントで保存 */
  RETAIN strec;
                                         /* 1回目のみ0で初期化 */
  IF _n_ = 1 THEN strec = 0 ; 
                                                 /* RECFM=n指定 */
  INFILE vbrec1 RECFM=n ;
                              /* 1バイトの識別データの読み込み */
                                   /* 行保持指示子"@"で行を保持 */
  INPUT @1+strec w_flg  1. @;
                                              /* 識別変数の選択 */
  SELECT(w_flg) ;
                                                    /* 条件 =1  */
    WHEN('1') DO;
      INPUT @2+strec  w_num1   4.
            @09+strec w_cdata1 $CHAR7.
            @16+strec w_cdata2 $CHAR10. 
            @27+strec w_nopd1  S370FPD4. 
            @32+strec w_nozd1  3. 
            @35+strec w_alld1  $CHAR166.
            @;
      OUTPUT work.rec1;
                                        /* 条件のレコード長指定 */
      endrec = 200;
                                 /* STRECへ次のレコード位置格納 */
      strec = strec + endrec ; 
    END;
                                                    /* 条件 =2  */
    WHEN('2') DO;
      INPUT @002+strec w_kdat1  $CHAR818.
            @820+strec w_cd1    4.    w_cd2 3.
            @827+strec w_date   YYMMDD10.
            @838+strec w_nopd1  S370FPD4. 
            @843+strec w_nozd1  3. 
            @846+strec w_alld2  $CHAR155.
            @;
      OUTPUT work.rec2 ;
                                        /* 条件のレコード長指定 */
      endrec = 1000;
                                 /* STRECへ次のレコード位置格納 */
      strec = strec + endrec ; 
    END;
     OTHERWISE DELETE;
    END;
                          /* DEBUG プログラム作成時のループ防止 */
  IF _N_ > 5; STOP;
RUN;