Class VariableLengthDataRecordFormatter

java.lang.Object
nablarch.core.dataformat.DataRecordFormatterSupport
nablarch.core.dataformat.VariableLengthDataRecordFormatter
All Implemented Interfaces:
Closeable, AutoCloseable, DataRecordFormatter

public class VariableLengthDataRecordFormatter extends DataRecordFormatterSupport
フォーマット定義ファイルの内容に従い、可変長ファイルデータの読み書きを行うクラス。

本クラスはスレッドセーフを考慮した実装にはなっていないので、呼び出し元で同期化の制御を行うこと。

ディレクティブの設定

可変長ファイルデータを読み込む際は、以下のディレクティブの設定が必須となる。

  • ファイルの文字エンコーディング
  • フィールド区切り文字(カンマ、タブなど)
  • レコード終端文字列(\n、\r、\r\nなど)

また、任意で以下の設定を行うことができる。

  • 囲み文字(デフォルトはダブルクォート)
  • 最初の行をタイトルとして読み書きするかどうか
  • 読み込みを許容する1行の文字列数(デフォルトは100万文字まで読み込み可能)

フィールド区切り文字および囲み文字は、任意の1文字を指定できる。
また、レコード終端文字列は、許容する文字列のみ指定できる。 デフォルトでは「\n」「\r」「\r\n」の3種類の文字列をレコード終端文字列として許容するが、 それを変更したい場合は、任意の許容する文字列のリストをFormatterFactoryクラスの allowedRecordSeparatorList プロパティに設定すること。

タイトル行の読み書き

requires-titleディレクティブにtrueを設定することで、タイトル行を読み書きする機能が有効となり、最初の行をタイトル行として通常のレコードタイプとは別に取り扱うことができるようになる。 この場合、最初の行はタイトル固定のレコードタイプ名[Title]で読み書きできるようになる。
(※ここでいうタイトルとは、ファイルの最初の行に存在し、個々のフィールドの論理名などが記載されるレコードのことを示す)

通常、タイトル行・データ行のような2つのレコードタイプが存在するファイルを読み込むためにはマルチフォーマットの定義を行う必要があるが、 タイトル行とデータ行に対してフォーマットの適用条件となるフィールドが存在しない場合、マルチフォーマットの定義では読み込むことができない。
しかし、本機能を使用すれば、最初の行はタイトル固有のレコードタイプが、最初の行以降はそれ以外のレコードタイプが適用されるので、 タイトル行とデータ行を識別するためのフィールドが存在しなくても、以下のとおりシングルフォーマットの定義で読み込むことができる。

 requires-title: true  # requires-titleがtrueの場合、最初の行をタイトルとして読み書きできる。
 
 [Title]               # タイトル固有のレコードタイプ。最初の行はこのレコードタイプで読み書きされる。
 1   Kubun      N  
 2   Name       N  
 3   Publisher  N  
 4   Authors    N  
 5   Price      N  
        
 [DataRecord]          # 最初の行以降の行はこのレコードタイプで読み書きされる。
 1   Kubun      X  
 2   Name       N  
 3   Publisher  N  
 4   Authors    N  
 5   Price      N  
 

また、本機能を使用する場合、最初の行がタイトル行であることが保証されるので、ファイルレイアウトのバリデーションを省略できるといったメリットもある。

以上の点より、最初の行にタイトルが存在するファイルを読み込む場合は、本機能を使用することを推奨する。

最初の行をタイトルとして読み書きする場合、以下の制約が発生する。この制約を満たさない場合、例外がスローされるので注意すること。

  • レコードタイプ [Title] を必ずフォーマット定義しなければならない。
  • 最初の行を書き込む際に指定するレコードタイプは [Title] でなければならない。
  • 最初の行以降を書き込む際に指定するレコードタイプは [Title] 以外でなければならない。
  • レコードタイプ [Title] にフォーマットの適用条件が定義されている場合、読み書きする最初の行は必ずその適用条件を満たさなければならない。また、最初の行以降の行はその適用条件を満たしてはいけない。

タイトル固有のレコードタイプ名はデフォルトでは [Title] だが、title-record-type-name ディレクティブでタイトル固有のレコードタイプ名を個別に指定することも可能である。

  • Constructor Details

    • VariableLengthDataRecordFormatter

      @Published(tag="architect") public VariableLengthDataRecordFormatter()
      デフォルトコンストラクタ。 デフォルトでは、VariableLengthConvertorSettingをコンバータとして使用する。
  • Method Details

    • initialize

      public DataRecordFormatter initialize()
      フォーマット定義情報保持クラスの初期化を行う。 初期化は本メソッドの1回目の実行時のみ行われ、2回目以降の実行時に初期化は行われない。

      また、入力ストリームをBufferedReaderにラップする処理および、 出力ストリームをBufferedWriterにラップする処理を行う。

      Specified by:
      initialize in interface DataRecordFormatter
      Overrides:
      initialize in class DataRecordFormatterSupport
      Returns:
      このオブジェクト自体
    • createDirectiveMap

      protected Map<String,DataRecordFormatterSupport.Directive> createDirectiveMap()
      使用するディレクティブの名前とDirectiveのMapを生成する。 サブクラスで使用するディレクティブを追加する場合は、本メソッドをオーバーライドし、任意のディレクティブを追加すること。
      Overrides:
      createDirectiveMap in class DataRecordFormatterSupport
      Returns:
      使用するディレクティブの名前と値の型のMap
    • validateDirectives

      protected void validateDirectives(Map<String,Object> directive)
      ディレクティブの内容の妥当性を検証する。

      サブクラスで独自のディレクティブを使用する場合は、このメソッドをオーバーライドし、独自のディレクティブに対して妥当性検証を行うこと。

      DataRecordFormatterでは以下の仕様を満たしているかどうかの検証を行う。

      • ディレクティブの値のデータ型が正しい
      • ファイルタイプが定義されている
      • エンコーディングが定義されている
      • エンコーディングがCharset型に変換できる
      • レコード終端文字列が許容されている文字である

      妥当性検証に失敗した場合は、SyntaxErrorExceptionがスローされる。

      Overrides:
      validateDirectives in class DataRecordFormatterSupport
      Parameters:
      directive - ディレクティブ
    • initializeField

      protected void initializeField(Map<String,Object> directive)
      フィールドを初期化する。

      DataRecordFormatterSupportでは、ディレクティブに設定された以下の値をフィールドに設定する。

      • レコード終端文字列
      • 文字エンコーディング

      VariableLengthDataRecordFormatterでは、ディレクティブまたはコンポーネント設定ファイルに設定された以下の値をフィールドに設定する。

      • 囲み文字
      • フィールド区切り文字
      • 空行をスキップするかどうか
      • 最初の行をタイトルとして読み書きするかどうか
      • タイトルのレコードタイプ名
      • 読み込みを許容する1行の文字列数
      • タイトルのレコードタイプ名
      Overrides:
      initializeField in class DataRecordFormatterSupport
      Parameters:
      directive - ディレクティブ
    • initializeFieldDefinition

      protected void initializeFieldDefinition()
      フィールド定義クラスについて、以下の初期化処理を行う。
      • コンバータ設定
      • エンコーディング設定
      • 差分定義が行われている場合は、親のフィールド定義情報を反映
      • レコード長、フィールド長の妥当性検証

      VariableLengthDataRecordFormatterでは、上記処理に加え、フォーマット定義が以下の条件を満たしているかどうかの検証を行う。条件を満たしていない場合、SyntaxErrorExceptionをスローする。

      • requires-titleディレクティブの値がtrueかつ、titleRecordTypeNameに設定されたレコードタイプ名と一致するレコードタイプがフォーマット定義されている。
      Overrides:
      initializeFieldDefinition in class DataRecordFormatterSupport
    • setInputStream

      public DataRecordFormatter setInputStream(InputStream stream)
      入力ストリームを設定する。
      Parameters:
      stream - 入力ストリーム
      Returns:
      本クラスのインスタンス
    • setOutputStream

      public DataRecordFormatter setOutputStream(OutputStream stream)
      出力ストリームを設定する。
      Parameters:
      stream - 出力ストリーム
      Returns:
      本クラスのインスタンス
    • readRecord

      @Published(tag="architect") public DataRecord readRecord() throws IOException
      入力ストリームから1レコード分のデータを読み込み、データレコードを返却する。 入力ストリームが既に終端に達していた場合はnullを返却する。
      Returns:
      データレコード
      Throws:
      IOException - 入力ストリームの読み込みに失敗した場合
    • validateFieldLength

      @Published(tag="architect") protected void validateFieldLength(List<String> fields, RecordDefinition recordDef)
      1レコード分のフィールド数が正しいかどうか検証する。
      Parameters:
      fields - フィールドのリスト
      recordDef - レコード定義情報保持クラス
    • initializeReader

      protected void initializeReader()
      フォーマット定義ファイルで指定されたエンコーディングで、可変長データを読み込むリーダを生成する。
    • convertToRecord

      @Published(tag="architect") protected DataRecord convertToRecord(List<String> fieldStrList, RecordDefinition recordDef) throws IOException
      読み込んだ1レコード分の文字列を、コンバータを用いてオブジェクトに変換し、返却する。
      Parameters:
      fieldStrList - 読み込んだフィールド文字列のリスト
      recordDef - レコード定義情報保持クラス
      Returns:
      データレコード
      Throws:
      IOException - 読み込みに伴うIO処理で問題が発生した場合。
    • convertToField

      protected Object convertToField(String fieldStr, FieldDefinition field)
      読み込んだフィールド文字列をコンバータを用いてオブジェクトに変換し、返却する。
      Parameters:
      fieldStr - 読み込んだフィールド文字列
      field - フィールド定義情報保持クラス
      Returns:
      コンバートしたフィールドの内容
    • writeRecord

      public void writeRecord(Map<String,?> record) throws IOException, InvalidDataFormatException
      出力ストリームに1レコード分の内容を書き込む。

      出力時に使用するデータレイアウト(レコードタイプ)は、Mapの内容をもとに自動的に判定される。

      引数がDataRecord型かつレコードタイプが指定されている場合、 フォーマット定義ファイルのレコードタイプ識別フィールド定義よりも、指定されたレコードタイプを優先して書き込みを行う。

      Parameters:
      record - 出力するレコードの内容を格納したMap
      Throws:
      IOException - 出力ストリームの書き込みに失敗した場合
      InvalidDataFormatException - 書き込むデータの内容がフォーマット定義に違反している場合
    • initializeWriter

      protected void initializeWriter()
      ライタを生成する。
    • writeRecord

      public void writeRecord(String recordType, Map<String,?> record) throws IOException
      指定したデータレイアウト(レコードタイプ)で、出力ストリームに1レコード分の内容を書き込む。
      Parameters:
      recordType - レコードタイプ
      record - 出力するレコードの内容を格納したMap
      Throws:
      IOException - 出力ストリームの書き込みに失敗した場合
    • writeRecord

      protected void writeRecord(Map<String,?> record, RecordDefinition recordType) throws IOException
      1レコード分の内容を、出力ストリームへ書き込む。
      Parameters:
      record - 出力するレコードの内容を格納したMap
      recordType - レコードタイプ
      Throws:
      IOException - 書き込みに伴うIO処理で問題が発生した場合。
    • writeField

      protected void writeField(Map<String,?> record, FieldDefinition field) throws IOException
      コンバータによる変換を行ったフィールドの内容を、出力ストリームへ書き込む。
      Parameters:
      record - 出力するレコードの内容を格納したMap
      field - フィールド定義情報保持クラス
      Throws:
      IOException - 書き込みに伴うIO処理で問題が発生した場合
    • readRecordAsString

      @Published(tag="architect") protected List<String> readRecordAsString() throws IOException
      入力ストリームから、1行分のレコードに存在するフィールドを、囲み文字などを取り除いた文字列のリストとして読み込む。
      Returns:
      1行分のレコードを変換した文字列のリスト
      Throws:
      IOException - 読み込みに伴うIO処理で問題が発生した場合。
    • consumeQuoteIfExists

      protected boolean consumeQuoteIfExists(Reader in, char quote) throws IOException
      後続の記号が囲み文字であれば読み込む。
      Parameters:
      in - 入力ストリーム
      quote - 囲み文字
      Returns:
      後続の記号が囲み文字であればtrue
      Throws:
      IOException - IOエラー
    • consumeSeparator

      protected String consumeSeparator(Reader in, Character fieldSeparator, String recordSeparator) throws IOException
      セパレータを読み込む。 セパレータが読み込めなければ実行時例外を送出する。
      Parameters:
      in - 入力ストリーム
      recordSeparator - レコード終端文字列
      fieldSeparator - フィールド区切り文字
      Returns:
      読み込んだ文字列
      Throws:
      IOException - IOエラー
    • endsWithString

      protected boolean endsWithString(String str, StringBuilder buff)
      バッファの末尾が指定した文字列で終了しているのであれば、 その文字列をバッファから除去した上でtrueを返却する。
      Parameters:
      str - 終了条件の文字列
      buff - バッファ
      Returns:
      バッファの末尾が指定した文字列で終了しているのであればtrue
    • endsWithChar

      protected boolean endsWithChar(Character character, StringBuilder buff)
      バッファの末尾が指定した1文字で終了しているのであれば、 その1文字をバッファから除去した上でtrueを返却する。
      Parameters:
      character - 1文字
      buff - バッファ
      Returns:
      バッファの末尾が指定した1文字で終了しているのであればtrue
    • hasNext

      public boolean hasNext() throws IOException
      次に読み込む行の有無を判定する。

      空行の存在を無視する設定の場合、ファイル末尾に空行が存在しても、次に読み込む行がないと判定する。

      Returns:
      次に読み込む行がある場合true
      Throws:
      IOException - 入力ストリームの読み込みに失敗した場合
    • hasNextIgnoreBlankLines

      @Published(tag="architect") protected boolean hasNextIgnoreBlankLines() throws IOException
      次に読み込む行があるかどうかを返却する。
      空行の存在を無視する設定の場合、ファイル末尾に空行が存在しても、次に読み込む行がないと判定する。
      Returns:
      次に読み込む行がある場合、true
      Throws:
      IOException - - IOエラー
    • close

      public void close()
      内部的に保持している各種リソースを開放する。 この実装では、setInputStream(java.io.InputStream)メソッドおよびsetOutputStream(java.io.OutputStream)メソッドで渡されたストリーム、 および内部でそれらをラップするReaderWriterのストリームをクローズする。
    • getConvertorSetting

      protected VariableLengthConvertorSetting getConvertorSetting()
      コンバータの設定情報保持クラスを取得する
      Specified by:
      getConvertorSetting in class DataRecordFormatterSupport
      Returns:
      コンバータの設定情報保持クラス
    • setDataTypeProperty

      protected DataRecordFormatterSupport setDataTypeProperty(DataType<?,?> datatype)
      空文字列をnullに変換するかどうかを各データタイプに設定する。
      Overrides:
      setDataTypeProperty in class DataRecordFormatterSupport
      Parameters:
      datatype - 対象のデータタイプ
      Returns:
      このオブジェクト自体