Direct I/O formatted text

この文書では、レコードやフィールドを区切り文字によって分割する様々なデータ形式を Direct I/O で取り扱うための機能「Direct I/O formatted text」について説明します。

概要

Direct I/O formatted text は、Direct I/Oで以下のようなデータ形式を持つテキストファイルを読み書きするための汎用的な機能を提供します。

  • レコード間が改行文字で区切られている
  • フィールド間が任意の1文字(タブやカンマなど)で区切られている
  • フィールドの位置(並び順)がフィールドの種類に対応する

特徴

Direct I/O formatted text は、以下のような特徴を持っています。

多様なデータ形式を扱うきめ細かな設定が可能

テキストファイルのエンコーディングやフィールド間の区切り文字をはじめ、 フィールド値の整形形式やエスケープの動作設定、 NULL や空文字に対する取り扱いなど、 様々なデータ形式に関する設定をレコード全体、及びフィールド単位にそれぞれ設定することができます。

従来、Direct I/Oでデータ取り込みを行うために事前にデータ整形処理が必要であったような場合においても、Direct I/O formatted textを利用することで直接そのようなデータを取り扱うことが可能になります。

不整合データに対する柔軟な動作設定が可能

データ形式の定義と実際のデータの内容に不整合があった場合に、 エラーとして異常終了とする、警告を出力して処理を継続する、または単にスキップするなど様々な動作がレコード全体、及びフィールド単位にそれぞれ設定可能です。 エラーや警告時にはエラー箇所と不整合の内容を示す詳細な情報が出力されます。

これらの機能によって想定外のデータに対して迅速に対応できるほか、外部システムやアプリケーションの仕様変更などに伴いアプリケーションとデータに不整合が発生するような場合でも、柔軟な運用、移行を可能にすることを支援します。

データフォーマットの作成

Direct I/O formatted text を利用したデータフォーマットを定義するには、対象のデータモデルに対応するDMDLスクリプトにDirect I/O formatted text用のデータモデル属性を指定します。

本バージョン時点で、Direct I/O formatted textは以下の2種類のデータモデル属性が利用できます。

  • @directio.text.tabular
  • @directio.text.csv

この2種類のデータモデル属性で取り扱うデータフォーマットはいずれも 概要 で示したようなテキストファイルを扱うものです。 その動作や設定可能な項目などは多くの部分で共通していますが、異なる部分は主にフィールド中のメタ文字に対する扱いと、デフォルトの設定です。 ここでのメタ文字とは、フィールド区切り文字などのファイルフォーマット自体に関わる文字のことです。

以下、それぞれのデータモデル属性が扱うデータフォーマットの概要と使い方を説明します。

@directio.text.tabular

@directio.text.tabular はフィールド中のメタ文字を「エスケープシーケンス」によって扱います。 エスケープシーケンスは「エスケープ文字+後続文字」という形式でフィールドデータとして表現します。エスケープ文字として使用する文字や、エスケープ時の動作などは @directio.text.tabular 属性の設定により細かく指定することが可能です。

デフォルトの設定はエスケープシーケンスは無効、フィールド間の区切り文字はHT(水平タブ)、といった設定を持ちます。

この形式に対応した DataFormat の実装クラスを自動的に生成するには、対象のデータモデルに対応するDMDLスクリプトに @directio.text.tabular を指定します。

@directio.text.tabular
document = {
    "the name of this document"
    name : TEXT;

    "the content of this document"
    content : TEXT;
};

上記のように記述してデータモデルクラスを生成すると、 <出力先パッケージ>.text.<データモデル名>TabularTextFormat というクラスが自動生成されます。 このクラスは DataFormat を実装し、データモデル内のプロパティが区切り文字によって分離されて順番に並んでいるようなテキストファイルを取り扱えます。

また、 単純な ファイルを入力に利用するDSLファイルを出力に利用するDSL の骨格も自動生成します。 前者は <出力先パッケージ>.text.Abstract<データモデル名>TabularTextInputDescription 、後者は <出力先パッケージ>.text.Abstract<データモデル名>TabularTextOutputDescription というクラス名で生成します。必要に応じて継承して利用してください。

@directio.text.csv

@directio.text.csvRFC 4180 で提唱されているCSVの形式に基いて、フィールド中のメタ文字を「クウォート」によって扱います。クウォート処理の基本的な動作は、フィールドにメタ文字が含まれる場合にフィールド全体をクウォート文字で囲うことで取り扱うものです。クウォート文字として使用する文字や、クウォート方式などは @directio.text.csv 属性の設定により細かく指定することが可能です。

デフォルトの設定はクウォート文字に " (ダブルクウォート)、フィールド間の区切り文字は , (カンマ)、といった設定を持ちます。

この形式に対応した DataFormat の実装クラスを自動的に生成するには、対象のデータモデルに対応するDMDLスクリプトに @directio.text.csv を指定します。

@directio.text.csv
document = {
    "the name of this document"
    name : TEXT;

    "the content of this document"
    content : TEXT;
};

上記のように記述してデータモデルクラスを生成すると、 <出力先パッケージ>.text.<データモデル名>CsvTextFormat というクラスが自動生成されます。 このクラスは DataFormat を実装し、データモデル内のプロパティが区切り文字によって分離されて順番に並んでいるようなテキストファイルを取り扱えます。

また、 単純な ファイルを入力に利用するDSLファイルを出力に利用するDSL の骨格も自動生成します。 前者は <出力先パッケージ>.text.Abstract<データモデル名>CsvTextInputDescription 、後者は <出力先パッケージ>.text.Abstract<データモデル名>CsvTextOutputDescription というクラス名で生成します。必要に応じて継承して利用してください。

他のデータフォーマット機能との関係

Direct I/O でテキストファイルを扱うには、本書で説明する Direct I/O formatted text の他にも以下のような機能を利用できます。

これらの機能と Direct I/O formatted text では提供する機能の一部が重複、または類似しているため、以下ではそれぞれの機能のおおまかな差異や使い分けの指針を説明していきます。

Attention

ここで説明する内容は現時点のもので、将来のバージョンで変更される可能性があります。

Direct I/O CSV

Direct I/O CSV と Direct I/O formatted text ( @directio.text.csv ) は両者とも RFC 4180 で提唱されているCSVの形式に基づいたデータフォーマットを扱う機能です。

機能面では、 Direct I/O formatted text は Direct I/O CSV よりも細かいデータフォーマットの指定が可能で、不整合データの取り扱いも柔軟に設定することができます。 Direct I/O CSV を利用する場合には事前にフォーマット整形が必要となるようなケースでは、Direct I/O formatted text によってより効率のよい対応が可能となる場合があります。

性能面では、現時点において Direct I/O CSV は Direct I/O formatted text よりも高速に動作します。 パフォーマンス差異の度合いは実行環境や扱うファイルの特性にも変わりますが、手元の検証ではおおよそ20%から30%程度、 Direct I/O CSV のほうが高速に動作するようです。

これらの機能の特性を考慮し、また実際に取り扱うデータフォーマットや実行環境の特性に応じて機能を選択するとよいでしょう。

Direct I/O TSV

Direct I/O TSV は TSV形式のデータフォーマットを使う機能ですが、 TSV形式のデータフォーマットについては Direct I/O formatted text を利用することを推奨します。

Direct I/O TSV は本バージョンでは非推奨機能です。その主な理由は本機能で対応可能なデータフォーマットが制限的で、汎用性に乏しいことによります。また不整合データの取り扱いについても他のデータフォーマット機能と比べて劣る部分があります。

なお、現時点で今後 Direct I/O TSV に関して大幅な拡張や変更を行う予定はありません。

Direct I/O line

Direct I/O line はファイル内の行文字列とデータモデル内の1つの文字列型プロパティをマッピングするシンプルな機能を提供します。

Direct I/O lineが想定する用途は主に2つあり、1つは JSONLTSV といった、レコードが1行で表現されるがデータの構成に区切り文字やフィールドの位置以外を利用するテキストデータフォーマットを取り扱う場合です。このような用途では引き続き Direct I/O line の利用を推奨します。

もう1つは、CSVやTSV形式の入力ファイルを扱いたいが、Direct I/O CSV や Direct I/O TSV が提供する機能では直接扱うことができず、テキスト内容の整形や形式変換、バリデーションチェックなどの事前処理が必要となる場合です。 このようなケースのいくつかは Direct I/O formatted text が提供する機能によって、直接データを扱うことが可能となる場合があります。

データフォーマットの設定

@directio.text.tabular および @directio.text.csv 属性の要素には、データフォーマットに関する次のような設定を指定することができます。

ここで指定する設定項目のうち、データフィールドに対して適用される設定については、全てのデータフィールドに共通の設定値として適用されます。 データフィールド単位で個別に設定を指定したい場合は、 後述の データフィールドの設定 を行うことでデータフィールド単位に設定を上書きすることができます。

以下はDMDLスクリプトの記述例です。

@directio.text.tabular(
    charset = "ISO-2022-JP",
    header = force,
    compression = "gzip",
    true_format = "1",
    false_format = "0",
    date_format = "yyyy/MM/dd",
    datetime_format = "yyyy/MM/dd HH:mm:ss",
)
model = {
    ...
};

テキスト全体の構成

charset

ファイルの文字セットエンコーディングを表す文字列。

指定した文字セットエンコーディングが ASCII または ASCIIの上位互換 のいずれでもない場合、 入力データの分割 が行われなくなる。

既定値: "UTF-8"

compression

ファイルの圧縮形式。 "gzip" または CompressionCodec [1] のサブタイプのクラス名を指定する。

ここで指定した圧縮形式で対象のファイルが読み書きされるようになるが、代わりに 入力データの分割 が行われなくなる。

既定値: 未指定 (圧縮無し)

line_separator

ファイル出力時に使用する、レコード間を区切るテキストの改行文字。以下のオプションから指定する。

  • unix : LF のみ
  • windows : CRLF の組み合わせ

入力時にはこの設定を利用せず、 LF, CR, CRLF のいずれも改行として扱う。 ただし CR のみの場合には 入力データの分割 が行われなくなる。

入力の末尾に改行文字が出現した場合、EOFとして扱う(次行を空レコードとして取り扱わない)。

既定値:

  • @directio.text.tabular : unix
  • @directio.text.csv : windows
field_separator

フィールド間の区切り文字。任意の1文字を指定する。

"\r" (CR), "\n" (LF), 及び escape_character で指定した値は指定できない。

既定値:

  • @directio.text.tabular : "\t" (HT:水平タブ)
  • @directio.text.csv : "," (カンマ)
[1]org.apache.hadoop.io.compress.CompressionCodec

ファイルヘッダの構成

header

ファイルヘッダの処理方法。以下のオプションから指定する。

  • nothing : 何もしない
  • force : 入力時に先頭行をスキップし、出力時に先頭行にヘッダを出力する
  • skip : 入力時に先頭行がヘッダにマッチすればスキップし、出力時はヘッダを出力しない
  • auto : 入力時に先頭行がヘッダにマッチすればスキップし、出力時に先頭行にヘッダを出力する

既定値: nothing

データ型の形式

true_format

データモデルの論理値型 ( BOOLEAN ) で TRUE を表す文字列。

false_format , null_format と同じ文字列は使用できない。

trim_input を利用した場合、 true_format の前後に空白文字が含まれているとマッチしない。

既定値: "true"

false_format

データモデルの論理値型 ( BOOLEAN ) で FALSE を表す文字列。

true_format , null_format と同じ文字列は使用できない。

trim_input を利用した場合、 false_format の前後に空白文字が含まれているとマッチしない。

既定値: "false"

number_format

データモデルの数値型 ( INT , LONG , FLOAT , DOUBLE , DECIMAL , BYTE , SHORT ) の形式。 DecimalFormat [2] の形式で指定する。

null を指定した場合は未指定として扱う。 未指定の場合はDirect I/O formatted textが規定する標準の方式で解析、及び出力を行う。

既定値: 未指定

decimal_output_style

データモデルの10進数型 ( DECIMAL ) の出力形式。以下のオプションから指定する。

  • plain : 指数表現なし
  • scientific : 必要ならば、指数表現を 10^n の単位で行う
  • engineering : 必要ならば、指数表現を 10^(n*3) の単位で行う

入力時にはこの設定を利用せず、全ての形式に対応する。

該当フィールドに number_format が指定されている場合、 decimal_output_style で指定した内容は無視される。

既定値: scientific

date_format

データモデルの日付型 ( DATE ) の形式。 SimpleDateFormat [3] の形式で指定する。

既定値: "yyyy-MM-dd"

datetime_format

データモデルの日時型 ( DATETIME ) の形式。 SimpleDateFormat の形式で指定する。

既定値: "yyyy-MM-dd HH:mm:ss"

null_format

NULL 値を表す形式。任意の文字列を指定する。

null を指定した場合は未指定として扱う。

NULL 値が未指定の場合、以下のような動作となる。

  • 入力データには NULL を表す値を含められない。
  • 出力データに NULL が含まれる場合には on_unmappable_output の設定に従ってエラー処理を行い、その結果ファイルの出力が実行される場合には、空文字列が出力される。

@directio.text.tabular を利用する場合には、 null 値の指定は escape_sequence の設定も利用される。その場合の動作を以下に示す。

  • null_format が未指定である場合、 escape_sequence で定義した null 値の設定を利用する。
  • escape_sequence でも null 値が未指定の場合、上記に示す「 NULL 値が未指定の場合」と同じ動作となる。
  • null_formatescape_sequence に両方 null 値が設定されている場合、 null_format の設定が優先して利用される。

既定値: 未指定

[2]java.text.DecimalFormat
[3]java.text.SimpleDateFormat

入力時の動作

trim_input

入力時に、フィールドの先頭末尾の空白文字を除去するかどうか。以下のオプションから指定する。

  • true : 除去する
  • false : 除去しない

この操作によってフィールドが空になった場合、 skip_empty_input の対象となる。

既定値: false

skip_empty_input

入力時に、フィールドの文字列が空である場合の動作。以下のオプションから指定する。

  • true : 読み飛ばす
  • false : 空文字列として扱う

既定値: false

on_malformed_input

入力時に、不正なフィールド文字列が検出された場合の動作。以下のオプションから指定する。

  • error : エラーログを出力して、異常終了する。
  • report : 警告ログを出力して、プロパティに NULL を設定する。
  • ignore : プロパティに NULL を設定する。

既定値: error

on_more_input

入力時に、レコードに余剰フィールドが検出された場合の動作。以下のオプションから指定する。

  • error : エラーログを出力して、異常終了する。
  • report : 警告ログを出力して、余剰フィールドを無視する。
  • ignore : 余剰フィールドを無視する。

既定値: error

on_less_input

入力時に、レコードにフィールドが不足している場合の動作。以下のオプションから指定する。

  • error : エラーログを出力して、異常終了する。
  • report : 警告ログを出力して、プロパティに NULL を設定する。
  • ignore : プロパティに NULL を設定する。

既定値: error

出力時の動作

on_unmappable_output

出力時に、不正な文字が含まれている場合の動作。以下のオプションから指定する。

  • error : エラーログを出力して、異常終了する。
  • report : 警告ログを出力して、そのまま出力。
  • ignore : そのまま出力。

データ内にエスケープやクウォートで対処できないメタ文字や、マッピングが未指定で NULL が存在した場合などに該当する。

既定値: error

エスケープ方式

エスケープ方式の設定は、 @directio.text.tabular 属性に対してのみ有効。

escape_character

エスケープシーケンス(エスケープ文字+後続文字)で使用するエスケープ文字。任意の1文字を指定する。

"\r" , "\n" , 及び field_separator で指定した値は指定できない。

既定値: 未指定 (エスケープシーケンスを利用できない)

escape_line_separator

改行文字をエスケープ可能にするかどうか。以下のオプションから指定する。

  • true - 改行文字をエスケープ可能にする。このオプションを指定した場合、 入力データの分割 が行われなくなる。
  • false - 改行文字をエスケープ不可能にする。

この設定を利用するには escape_character も定義する必要がある。

既定値: false

escape_sequence

利用可能なエスケープの一覧。マップ形式 ( { "キー":"値", "キー":"値", ... } ) で指定する。

キー

キーにはエスケープシーケンスの後続文字(エスケープ文字を除いた1文字)を指定する。

キーには "\r" , "\n" といった、改行文字の構成要素を含められない。 改行文字のエスケープするための設定は escape_line_separator で指定する。

値にはシーケンスに対応する1文字を指定する。

値にはNULLを表す特別なシンボル null を利用出来る。 フィールド全体がそのシーケンスのみの値である場合、そのフィールド値はNULLとしてエスケープされる。

サロゲートペアはキー・値のいずれにも利用できない。

この設定を利用するには escape_character も定義する必要がある。

既定値: なし

クウォート方式

クウォート方式の設定は、 @directio.text.csv 属性に対してのみ有効。

quote_character

フィールドのクウォートで使用するクウォート文字。

"\r" , "\n" , 及び field_separator で指定した値は指定できない。

既定値: "\"" (ダブルクウォート)

allow_linefeed

フィールドにLF(改行文字)を含められるかどうか。以下のオプションから指定する。

  • true : 含められる。このオプションを指定した場合、 入力データの分割 が行われなくなる。
  • false : 含められない。フィールドにLFが含まれる場合はエラーとして扱う。

既定値: false

quote_style

出力時のクォート方式。以下のオプションから指定する。

  • always : 常にクウォートを行う。
  • never : 常にクウォートを行わない。フィールドに CR, LF, field_separator, quote_character のいずれかが含まれる場合はエラーとして扱う。
  • needed : フィールドに CR, LF, field_separator, quote_character のいずれかが出現した場合のみクウォートを行う。

入力時にはこの設定を利用せず、全てのクウォート方式に対応する。

既定値: needed

header_quote_style

出力時ヘッダのクォート方式。以下のオプションから指定する。

  • always : 常にクウォートを行う。
  • never : 常にクウォートを行わない。フィールドに CR, LF, field_separator, quote_character のいずれかが含まれる場合はエラーとして扱う。
  • needed : フィールドに CR, LF, field_separator, quote_character のいずれかが出現した場合のみクウォートを行う。

入力時にはこの設定を利用せず、全てのクウォート方式に対応する。

未指定の場合、 quote_style と同じクウォート方式を利用する。

既定値: 未指定

データフィールドの設定

Direct I/O formatted text が扱うテキストファイルのデータフィールドに関する設定は、DMDLスクリプトのデータモデルに含まれるそれぞれのプロパティに @directio.text.field 属性を指定します。

@directio.text.field 属性の要素には、次のような設定を指定することができます。

その他、データフィールドに対する個別の属性を利用した、次のような設定を指定することができます。

以下はDMDLスクリプトの記述例です。

@directio.text.tabular (
    ...
)
model = {
    @directio.text.field (
        name = "数量",
        null_format = "",
        on_unmappable_output = report,
    )
    amount : INT;
};

フィールドの基本情報

name

フィールド名を表す文字列。

header の設定によりファイルヘッダを出力する場合、ここで指定したフィールド名がヘッダに利用される。未指定の場合、プロパティ名がヘッダに利用される。

既定値: 未指定

フィールドのデータフォーマット

データフォーマットの設定 が持つ設定のうち、次の項目については @directio.text.field 属性に同名の要素を指定することでデータフィールド単位に設定を上書きすることができます。

フィールドの除外

データモデルに定義されている特定のプロパティをデータフィールドとして取り扱いたくない場合の設定です。

@directio.text.ignore
このプロパティをデータフィールドとして取り扱わない。

ファイル情報の取得

入力時のテキストファイルに関する情報を取得する場合、それぞれ次の属性をプロパティに指定します。

これらの属性はファイル入力時のみ有効です。 これらの属性を指定したプロパティは、ファイル出力時にはデータフィールドから除外されます。

@directio.text.file_name

このフィールドに、該当データレコードが含まれるファイルパスを設定する。

この属性を指定するプロパティには TEXT 型を指定する必要がある。

@directio.text.line_number

このフィールドに、該当データレコードの開始行番号(テキスト行番号)を設定する。

この属性を指定するプロパティには INT または LONG 型を指定する必要がある。

この属性が指定された場合、 入力データの分割 が行われなくなる。

@directio.text.record_number

このフィールドに、該当データレコードのレコード番号を設定する。

この属性を指定するプロパティには INT または LONG 型を指定する必要がある。

この属性が指定された場合、 入力データの分割 が行われなくなる。

設定例

エスケープシーケンス

@directio.text.tabular でエスケープシーケンスを利用するための設定例です。 ここでは以下のようなエスケープシーケンスを定義します。

  • \ をエスケープ文字に指定
  • 改行文字 \r , \n , タブ \t をエスケープ
  • エスケープ文字自体をエスケープ
  • \N をNULLとして扱う
@directio.text.tabular (
    escape_character = "\\",
    escape_sequence = {
      "r" : "\r",
      "n" : "\n",
      "t" : "\t",
      "\\" : "\\",
      "N" : null,
    },
)
...

Note

DMDLスクリプト内ではJavaの文字列リテラルと同様に \ はエスケープシーケンスとして扱われるため、各要素の値に \ を指定したい場合は "\\" のようにバックスラッシュを2つ記述します。

空文字列とNULLの扱い

Direct I/O formatted textでは、空文字列とNULLに関して標準では以下のように設定されています。

  • skip_empty_input = false (フィールド値が空値の場合は空文字列として扱う)
  • null_format = (未指定)

これらの設定により、標準の動作は以下のような強い制約を伴います。

  • 入力ファイル内のフィールド値が空文字列となっている場合、そのフィールドが TEXT 型以外のプロパティと対応付けられていると不正な値として扱われる。
  • 出力時にデータモデル内のプロパティ値に null が含まれると不正な値として扱われる。

データモデル全体で空文字列を NULL として扱う場合は、以下のように null_format を設定します。

@directio.text.csv (
    null_format = "",
)
...

Note

上記のデータモデル全体で空文字列を NULL として扱う動作は Direct I/O CSV と同じ動作となります。 Direct I/O CSV から Direct I/O formatted text ( @directio.text.csv ) に移行するなどで、 Direct I/O CSV と同様の動作に設定したい場合には上例のように設定してください。

数値型のプロパティのみに対して空文字列を NULL として扱うなど、フィールド単位で null_format を設定することもできます。

@directio.text.csv (
    ...
)
model = {
    @directio.text.field (
        null_format = "",
    )
    amount : INT;
};

null_format による設定のほかに、不正な値を検出した場合の動作を変更し処理を続行させる方法もあります。 以下の設定は、数値型のフィールドに空文字列などの不正なフォーマットを検出した場合に警告を出力し、空文字列と null を相互にマッピングします。

@directio.text.csv (
    ...
)
model = {
    @directio.text.field (
        on_malformed_input = report,
        on_unmappable_output = report,
    )
    amount : INT;
};

Attention

null_format が未指定の場合、テストドライバのジョブフローやバッチのテスト実行時にテストドライバが NULL を取り扱う動作にも注意が必要です。

例えば Excelによるテストデータ定義 などの方法で入力データを定義する際には、テストケースで利用しないプロパティを未定義にすることができますが、その際テストドライバは未定義のプロパティをNULLとして取り扱います。また同様に空のセルもNULLとして扱います。

テストドライバの NULL 値の扱いについては、 Excelによるテストデータ定義 などのテストドライバのドキュメントを確認してください。