    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.model;
    017
    018import org.opengion.fukurou.system.OgRuntimeException;                                                  // 6.4.2.0 (2016/01/29)
    019import org.opengion.fukurou.util.StringUtil;                                                                    // 6.2.0.0 (2015/02/27)
    020import org.opengion.fukurou.util.FileInfo;                                                                              // 6.2.0.0 (2015/02/27)
    021
    022import java.util.List;
    023import java.util.ArrayList;
    024import java.util.Map;                                                                                                                   // 6.1.0.0 (2014/12/26) ConstData を Mapで管理
    025import java.util.HashMap;                                                                                                               // 6.1.0.0 (2014/12/26) ConstData を Mapで管理
    026import java.util.Arrays;                                                                                                                // 6.2.0.0 (2015/02/27)
    027import java.io.File;                                                                                                                    // 6.2.0.0 (2015/02/27)
    028
    029/**
    030 * EXCELやﾃｷｽﾄﾌｧｲﾙを、ｲﾍﾞﾝﾄ方式に準拠して、読み込み処理を行います。
    031 * TableModelHelperｲﾍﾞﾝﾄは、openGion形式のﾌｧｲﾙ読み取りに準拠した方法をｻﾎﾟｰﾄします。
    032 * ※ openGion形式のEXCEL/ﾃｷｽﾄﾌｧｲﾙとは、#NAME 列に、ｶﾗﾑ名があり、#で始まる
    033 *    ﾚｺｰﾄﾞは、ｺﾒﾝﾄとして判断し、読み飛ばす処理の事です。
    034 *
    035 * このｲﾍﾞﾝﾄｸﾗｽは、ｻﾌﾞｸﾗｽを作成し、EXCEL関連の EventReader_XLS、EventReader_XLSX
    036 * ｸﾗｽや、EventReader_TEXT などのﾃｷｽﾄ関連のｸﾗｽで、eventReader ﾒｿｯﾄﾞの引数に指定します。
    037 * EventReader_XLS と、EventReader_XLSX は、対象のEXCEL形式が異なりますが、実際は、
    038 * POIUtil#eventReader( String , TableModelHelper ) を使用すれば、拡張子に応じて使用するｸﾗｽを
    039 * 選択します。
    040 *
    041 * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    042 * @og.rev 6.2.0.0 (2015/02/27) ﾊﾟｯｹｰｼﾞ変更(util → model),ｸﾗｽ名変更(ExcelReaderEvent → TableModelHelper)
    043 * @og.group ﾌｧｲﾙ入力
    044 *
    045 * @version     6.0
    046 * @author      Kazuhiko Hasegawa
    047 * @since       JDK7.0,
    048 */
    049public class TableModelHelper {
    050        private int                             nowRowNo        = -1;                                                                   // 現在の行番号
    051        private boolean                 isColSkip       ;                                                                               // ｶﾗﾑｽｷｯﾌﾟ中かどうか(true:ｽｷｯﾌﾟ中)
    052        private boolean                 isNowName       ;                                                                               // ｶﾗﾑ名配列の収集中かどうか(true:収集中)
    053        private boolean                 isReadBreak     ;                                                                               // 読み取り処理を途中で中止するかどうか(true:中止)
    054        private String                  nullBreakClm;                                                                           // ﾃﾞｰﾀがnullまたはｾﾞﾛ文字列の場合に、Sheet読み取りを停止
    055        private String                  nullSkipClm     ;                                                                               // 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
    056
    057        private int                             skipRowCnt      ;                                                                               // 読み飛ばす行数(読み飛ばし中でも ContDataは取得する)
    058        private int                             nBrkClmNo = -1;                                                                         // nullBreakClmの列番号
    059        private int                             nSkpClmNo = -1;                                                                         // 6.2.3.0 (2015/05/01) nullSkipClmの列番号
    060
    061        private int                             clmSize = -1 ;                                                                          // ｶﾗﾑｻｲｽﾞ(-1は未設定)
    062        private String[]                names           ;                                                                               // ｶﾗﾑ名配列
    063        private int[]                   colms           ;                                                                               // ｶﾗﾑ番号配列 7.3.1.3 (2021/03/09) colList をﾃﾝﾎﾟﾗﾘにするため
    064        private String[]                vals            ;                                                                               // 値の文字列配列(1行分)
    065        private boolean                 useVals         ;                                                                               // 値配列に設定されたか？
    066
    067        private List<Integer>   colList ;                                                                                       // ｶﾗﾑ番号:name が null かｾﾞﾛ文字列の場合は、飛ばします。
    068        private List<String>    nmsList ;                                                                                       // ｶﾗﾑ番号に対応したｶﾗﾑ名配列(#NAMEの場合のみ使用)
    069
    070        private ConstData               cnstData        ;
    071
    072        private boolean                 useDebug        ;                                                                                       // 6.2.0.0 (2015/02/27) ﾃﾞﾊﾞｯｸﾞ情報の出力するかどうか。新規追加
    073
    074        /**
    075         * ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰ
    076         *
    077         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    078         */
    079        public TableModelHelper() { super(); }          // これも、自動的に呼ばれるが、空のﾒｿｯﾄﾞを作成すると警告されるので、明示的にしておきます。
    080
    081        /**
    082         * ﾌｧｲﾙの読み取り開始時にｲﾍﾞﾝﾄが発生します。
    083         *
    084         * 新しいﾌｧｲﾙの読み取り開始毎に、1回呼ばれます。
    085         * 戻り値が、true の場合は、そのﾌｧｲﾙの読み取りを継続します。
    086         * false の場合は、そのﾌｧｲﾙの読み取りは行われません。
    087         * 初期実装では、固定値設定処理を行っていますので、ｵｰﾊﾞｰﾗｲﾄﾞする場合は、
    088         * super.startFile(String,int) してください。
    089         * 初期実装では、true を返します。
    090         *
    091         * @og.rev 6.2.0.0 (2015/02/27) 新規作成
    092         *
    093         * @param       file    読み取りﾌｧｲﾙ
    094         * @return      読取継続するか [true:継続/false:読取らない]
    095         */
    096        public boolean startFile( final File file ) {
    097                if( useDebug ) { System.out.println( "startFile=[" + file + "]" ); }
    098                // ﾌｧｲﾙ属性を設定する。
    099                if( cnstData != null ) { cnstData.putConstFile( file ); }
    100                return true;
    101        }
    102
    103        /**
    104         * ﾌｧｲﾙの読み取り終了時にｲﾍﾞﾝﾄが発生します。
    105         *
    106         * 初期実装では、固定値設定処理を行っていますので、ｵｰﾊﾞｰﾗｲﾄﾞする場合は、
    107         * super.endFile(File) してください。
    108         *
    109         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    110         * @og.rev 6.1.0.0 (2014/12/26) ｼｰﾄﾌﾞﾚｲｸ処理追加
    111         *
    112         * @param       file    読み取りﾌｧｲﾙ
    113         */
    114        public void endFile( final File file ) {
    115                if( useDebug ) { System.out.println( "endFile=[" + file + "]" ); }
    116                isReadBreak = false;                    // 読み取り再開
    117                endRow();                                               // 行終了処理
    118                if( cnstData != null ) { cnstData.clearValsMap( ConstData.END_FILE ); }
    119        }
    120
    121        /**
    122         * ｼｰﾄの読み取り開始時にｲﾍﾞﾝﾄが発生します。
    123         *
    124         * ※ EXCEL関係以外の読み取りでは、このｲﾍﾞﾝﾄは発生しません。
    125         *
    126         * 新しいｼｰﾄの読み取り開始毎に、1回呼ばれます。
    127         * 戻り値が、true の場合は、そのｼｰﾄの読み取りを継続します。
    128         * false の場合は、そのｼｰﾄの読み取りは行わず、次のｼｰﾄまで
    129         * ｲﾍﾞﾝﾄは発行されません。
    130         * 初期実装では、固定値設定処理を行っていますので、ｵｰﾊﾞｰﾗｲﾄﾞする場合は、
    131         * super.startSheet(String,int) してください。
    132         * 初期実装では、true を返します。
    133         *
    134         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    135         *
    136         * @param       shtNm   ｼｰﾄ名
    137         * @param       shtNo   ｼｰﾄ番号(0～)
    138         * @return      読取継続するか [true:継続/false:読取らない]
    139         */
    140        public boolean startSheet( final String shtNm,final int shtNo ) {
    141                if( useDebug ) { System.out.println( "startSheet=[" + shtNm + "], No=[" + shtNo + "]" ); }
    142                // ｼｰﾄ名を設定する。
    143                if( cnstData != null ) { cnstData.putConstSheet( shtNm ); }
    144                return true;
    145        }
    146
    147        /**
    148         * ｼｰﾄの読み取り終了時にｲﾍﾞﾝﾄが発生します。
    149         *
    150         * ※ EXCEL関係以外の読み取りでは、このｲﾍﾞﾝﾄは発生しません。
    151         *
    152         * #columnNames( String[] ) や、#values( String[] ,int ) などは、行の処理が完了した時点で
    153         * ｲﾍﾞﾝﾄが呼ばれるため、一番最後のﾚｺｰﾄﾞの終了条件が判りません。
    154         * そこで、このｲﾍﾞﾝﾄを呼ぶことで、ｼｰﾄの終了(=最終行の終了)処理を行うことができます。
    155         *
    156         * 引数のｼｰﾄ番号は、参考情報で、#startSheet( String,int ) で呼ばれたｼｰﾄ番号と
    157         * 比較できるようにしています。
    158         * 初期実装では、固定値設定処理を行っていますので、ｵｰﾊﾞｰﾗｲﾄﾞする場合は、
    159         * super.endSheet(int) してください。
    160         *
    161         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    162         * @og.rev 6.1.0.0 (2014/12/26) ｼｰﾄﾌﾞﾚｲｸ処理追加
    163         *
    164         * @param       shtNo   ｼｰﾄ番号(0～)
    165         */
    166        public void endSheet( final int shtNo ) {
    167                if( useDebug ) { System.out.println( "endSheet No=[" + shtNo + "]" ); }
    168                isReadBreak = false;                    // 読み取り再開
    169                endRow();                                               // 行終了処理
    170                if( cnstData != null ) { cnstData.clearValsMap( ConstData.END_SHEET ); }
    171        }
    172
    173        /**
    174         * 読み取り状態の時に、rowNo にある行ﾃﾞｰﾀを引数にｲﾍﾞﾝﾄが発生します。
    175         *
    176         * ※ 主に、行ﾃﾞｰﾀの読み込み処理で使用されるﾒｿｯﾄﾞです。
    177         *    このﾒｿｯﾄﾞは、EventReader#eventReader( String , TableModelHelper )ﾒｿｯﾄﾞの
    178         *    処理の過程で、設定されます。
    179         *    このﾒｿｯﾄﾞから、各種ｲﾍﾞﾝﾄが発行されます。
    180         *
    181         * 行ﾃﾞｰﾀをｾﾊﾟﾚｰﾀで分解したのち、value( String ,int ,int ) ﾒｿｯﾄﾞを呼びます。
    182         * ただし、行ﾃﾞｰﾀが、null、空文字列、#で始まる場合は、呼ばれません。
    183         *
    184         * @og.rev 6.2.0.0 (2015/02/27) 新規作成
    185         * @og.rev 6.2.1.0 (2015/03/13) 先頭に、'0 が含まれる場合のｾﾐｺﾛﾝや、前後のﾀﾞﾌﾞﾙｸｵｰﾄは削除
    186         * @og.rev 6.2.5.0 (2015/06/05) ﾃﾞﾊﾞｯｸ時に1行単位に出力するのを止めます。
    187         * @og.rev 7.1.0.0 (2020/01/27) ｾﾊﾟﾚｰﾀ分割時にﾃﾞｰﾀ分割されない場合は、ｴﾝｺｰﾄﾞｴﾗｰの可能性が高い。
    188         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのｵﾘｼﾞﾅﾙを取得できるようにします。
    189         * @og.rev 8.4.0.0 (2022/12/23) 7.1.0.0 (2020/01/27) の対応は、ReadTableTag に移動。
    190         *
    191         * @param       line    行ﾃﾞｰﾀ
    192         * @param       rowNo   行番号(0～)
    193         * @param       sepa    ｾﾊﾟﾚｰﾀ
    194         */
    195        protected void value( final String line,final int rowNo,final char sepa ) {
    196                nowRowNo = rowNo;       // 現在行の設定
    197
    198                // 値が存在する場合のみ、処理する。
    199                if( line!=null && !line.isEmpty() ) {
    200                        // 6.2.5.0 (2015/06/05) ﾃﾞﾊﾞｯｸ時に1行単位に出力するのを止めます。
    201        //              if( useDebug ) { System.out.println( "rowNo[" + rowNo + "], line=[" + line + "]" ); }
    202
    203                        // 先頭ｶﾗﾑのｺﾒﾝﾄ判断と、#NAME列判断
    204                        if( line.charAt(0)=='#' ) {
    205                                // 互換性の問題。#NAME は、大文字小文字両方対応できないといけない。( 5 == "#NAME".length() の事)
    206                                // 7.3.1.3 (2021/03/09) #NAME があれば処理する。
    207//                              if( clmSize <= 0 && line.length() >= 5 && "#NAME".equalsIgnoreCase( line.substring( 0,5 ) ) ) {
    208                                if( line.length() >= 5 && "#NAME".equalsIgnoreCase( line.substring( 0,5 ) ) ) {
    209                                        colList = new ArrayList<>() ;                                                           // 初期化
    210                                        nmsList = new ArrayList<>() ;                                                           // 初期化
    211                                        final String[] tmpNm = StringUtil.csv2Array( line,sepa );
    212                                        for( int colNo=1; colNo<tmpNm.length; colNo++ ) {                       // #NAME を無視(colNo=1～)
    213                                                final String nm = tmpNm[colNo];
    214                                                // #NAME 設定も、null や、ｾﾞﾛ文字列の場合は、登録しない。(一番上の if で対処)
    215                                                if( nm != null && !nm.isEmpty() ) {
    216                                                        colList.add( Integer.valueOf( colNo ) );
    217                                                        nmsList.add( nm );
    218                                                }
    219                                        }
    220                                        originalNames( nmsList.toArray( new String[nmsList.size()] ) ); // 7.3.1.3 (2021/03/09) #NAMEのｵﾘｼﾞﾅﾙを取得
    221                                        isNowName = true;
    222                                }
    223                        }
    224                        // clmSize > 0 は、#NAME が設定済みという意味
    225                        else if( clmSize > 0 && skipRowCnt <= rowNo ) {                                         // skipRowCnt は、値ｾｯﾄだけ影響する。
    226                                final String[] tmpVals = StringUtil.csv2Array( line ,sepa );
    227        //                      if( cnstData != null ) { tmpVals = cnstData.getConstVals( tmpVals ); }
    228        //                      int min = Math.min( clmSize,tmpVals.length );
    229
    230                //              // 8.4.0.0 (2022/12/23) 7.1.0.0 (2020/01/27) の対応は、ReadTableTag に移動。
    231                //              // 7.1.0.0 (2020/01/27) ｴﾝｺｰﾄﾞによってはｴﾗｰにならず1ｶﾗﾑのﾃﾞｰﾀとして取れてしまう。
    232                //              // ｶﾗﾑ数が1以上で、ﾃﾞｰﾀ数が1の場合は、取り込みﾐｽなので処理を終了する。
    233                //              if( clmSize > 1 && tmpVals.length == 1 ) {
    234                //                      isReadBreak = true;                                                                                     // 処理の停止
    235                //                      clmSize     = 0;                                                                                        // #NAME列未設定と同じ(-1にしないのは、単に初期値と違うという事)
    236                //                      return ;                                                                                                        // 即抜ける
    237                //              }
    238
    239                                for( int i=0; i<clmSize; i++ ) {
    240//                                      final int indx = colList.get( i );                                                      // ｶﾗﾑ番号の位置が 値配列の配列番号
    241                                        final int indx = colms[i];                                                                      // 7.3.1.3 (2021/03/09) ｶﾗﾑ番号の位置が 値配列の配列番号
    242                                        if( indx >= 0 && indx < tmpVals.length ) {
    243                                                vals[i] = StringUtil.csvOutQuote( tmpVals[indx] );              // 6.2.1.0 (2015/03/13)
    244                                        }
    245                                }
    246                                useVals = true;
    247        //                      values( vals , rowNo );                                                                                 // ｲﾍﾞﾝﾄ発行(現在行)
    248                        }
    249
    250                        endRow();                                                                                                                       // 行末処理実行。名前設定処理が走ります。
    251                }
    252        }
    253
    254        /**
    255         * 読み取り状態の時に、rowNo,colNo にあるｾﾙの値を引数にｲﾍﾞﾝﾄが発生します。
    256         *
    257         * ※ 主に、EXCEL関係の読み取り処理で使用されるﾒｿｯﾄﾞです。
    258         *    このﾒｿｯﾄﾞは、EventReader#eventReader( String , TableModelHelper )ﾒｿｯﾄﾞの
    259         *    処理の過程で、設定されます。
    260         *    このﾒｿｯﾄﾞから、各種ｲﾍﾞﾝﾄが発行されます。
    261         *
    262         * 戻り値が、true の場合は、その行の読み取りを継続します。
    263         * false の場合は、その行の読み取りは行わず、次の行まで
    264         * ｲﾍﾞﾝﾄは発行されません。
    265         *
    266         * openGion での標準的な処理は、colNo==0 の時に、val の先頭が、# で
    267         * 始まる場合は、その行はｽｷｯﾌﾟします。
    268         * ここでの return は、#isSkip( int ) と逆になりますので、ご注意ください。
    269         * 初期実装では、#NAME処理、行ｽｷｯﾌﾟ、行終了処理等を実行します。
    270         * ｵｰﾊﾞｰﾗｲﾄﾞする場合は、super.value(String,int,int) してください。
    271         *
    272         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    273         * @og.rev 6.2.2.0 (2015/03/27) 先頭に、'0 が含まれる場合のｾﾐｺﾛﾝや、前後のﾀﾞﾌﾞﾙｸｵｰﾄは削除
    274         * @og.rev 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
    275         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのｵﾘｼﾞﾅﾙを取得できるようにします。
    276         *
    277         * @param       val             文字列値
    278         * @param       rowNo   行番号(0～)
    279         * @param       colNo   列番号(0～)
    280         * @return      読み取りするかどうか(true:読み取りする/false:読み取りしない)
    281         * @see         #isSkip( int )
    282         */
    283        protected boolean value( final String val,final int rowNo,final int colNo ) {
    284        //      if( useDebug ) { System.out.println( "R[" + rowNo + "," + colNo + "]=" + val ); }
    285
    286                // 値が存在する場合のみ、処理する。
    287                if( val!=null && val.length()>0 ) {
    288                        // 行番号が異なった場合は、行の終了処理を実行する。
    289                        if( nowRowNo != rowNo ) {
    290                                if( isNowName ) {                                                                                               // 7.3.1.3 (2021/03/09) #NAMEのｵﾘｼﾞﾅﾙを取得
    291                                        originalNames( nmsList.toArray( new String[nmsList.size()] ) );
    292                                }
    293
    294                                endRow();                                                                                                               // 行終了処理
    295                                nowRowNo = rowNo;                                                                                               // 現在行の設定
    296                        }
    297
    298                        // 固定文字の設定なので、ｺﾒﾝﾄもｽｷｯﾌﾟも無関係
    299                        if( cnstData != null ) { cnstData.putConstValue( val,rowNo,colNo ); }
    300
    301                        // 先頭ｶﾗﾑのｺﾒﾝﾄ判断と、#NAME列判断
    302                        if( colNo==0 && val.charAt(0)=='#' ) {
    303//                              if( "#NAME".equalsIgnoreCase( val ) && clmSize <= 0 ) {                 // clmSize <= 0 は、#NAME未設定という意味
    304                                // 7.3.1.3 (2021/03/09) #NAME があれば処理する
    305                                if( "#NAME".equalsIgnoreCase( val )) {
    306                                        isNowName = true ;
    307                                        colList = new ArrayList<>() ;                                                           // 初期化
    308                                        nmsList = new ArrayList<>() ;                                                           // 初期化
    309                                }
    310                                isColSkip = !isNowName;                                                                                 // #NAME の場合は、false(SKIPしない)
    311                        }
    312                        // #NAME処理中
    313                        else if( isNowName ) {
    314                                // #NAME 設定も、null や、ｾﾞﾛ文字列の場合は、登録しない。(一番上の if で対処)
    315                                colList.add( Integer.valueOf( colNo ) );
    316                                nmsList.add( val );
    317                        }
    318                        // 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
    319                        else if( nSkpClmNo >= 0 && StringUtil.isNull( vals[nSkpClmNo] ) ) {     // nullSkipClm 処理
    320                                isColSkip = true;       // Skip する
    321                        }
    322                        // clmSize > 0 は、#NAME が設定済みという意味
    323                        // 7.3.1.3 (2021/03/09) ｶﾗﾑ番号の位置が 値配列の配列番号
    324                        else if( clmSize > 0 && skipRowCnt <= rowNo ) {                                         // skipRowCnt は、値ｾｯﾄだけ影響する
    325                                for( int i=0; i<clmSize ; i++ ) {                                                               // ｶﾗﾑ番号の位置が 値配列の配列番号
    326                                        if( colms[i] == colNo ) {
    327                                                vals[i] = StringUtil.csvOutQuote( val );                                // 6.2.2.0 (2015/03/27)
    328                                                useVals = true;
    329                                                break;
    330                                        }
    331                                }
    332                        }
    333//                      else if( clmSize > 0 && skipRowCnt <= rowNo ) {                                         // skipRowCnt は、値ｾｯﾄだけ影響する。
    334//                              final int indx = colList.indexOf( Integer.valueOf( colNo ) );   // ｶﾗﾑ番号の位置が 値配列の配列番号
    335//                              if( indx >= 0 ) {
    336//                                      vals[indx] = StringUtil.csvOutQuote( val );                                     // 6.2.2.0 (2015/03/27)
    337//                                      useVals = true;
    338//                              }
    339//                      }
    340                }
    341
    342                return !isColSkip;
    343        }
    344
    345        /**
    346         * rowNo を元に、この行をｽｷｯﾌﾟするかどうか判定のｲﾍﾞﾝﾄが発生します。
    347         *
    348         * ※ EXCEL関係の列毎にｲﾍﾞﾝﾄが発生する場合の列処理をｽｷｯﾌﾟするのが目的です。
    349         *    行単位に読み込む場合や、行のﾙｰﾌﾟに入れても、意味はありません。
    350         *    引数から、行のﾙｰﾌﾟに入れてしまいそうですが、行列のﾙｰﾌﾟに入れてください。
    351         *
    352         * ※ 主に、EXCEL関係の読み取り処理で使用されるﾒｿｯﾄﾞです。
    353         *    このﾒｿｯﾄﾞは、EventReader#eventReader( String , TableModelHelper )ﾒｿｯﾄﾞの
    354         *    処理の過程で、設定されます。
    355         *    このﾒｿｯﾄﾞから、各種ｲﾍﾞﾝﾄが発行されます。
    356         *
    357         * 戻り値が、true の場合は、その行の読み取りをｽｷｯﾌﾟします。
    358         * false の場合は、読み取り処理を継続します。
    359         * ｽｷｯﾌﾟ中は、行に関するｲﾍﾞﾝﾄは発行されません。
    360         *
    361         * 値(val)を求める前に、行情報を入手し、ｽｷｯﾌﾟ中の現在行と同じ場合に、ｽｷｯﾌﾟ(=true)と判定します。
    362         * ｽｷｯﾌﾟ中かどうかは、#value( String,int,int ) で、判定します。
    363         * 初期実装では、ｽｷｯﾌﾟ中 かつ 現在行と同じ行の場合、または、ｼｰﾄﾌﾞﾚｰｸ中の場合に、true を返します。
    364         *
    365         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    366         * @og.rev 6.1.0.0 (2014/12/26) ｼｰﾄﾌﾞﾚｲｸ処理追加
    367         *
    368         * @param       rowNo   行番号(0～)
    369         * @return      ｽｷｯﾌﾟするかどうか(true:ｽｷｯﾌﾟする/false:ｽｷｯﾌﾟしない)
    370         * @see         #value( String,int,int )
    371         */
    372        protected boolean isSkip( final int rowNo ) {
    373                return isColSkip && nowRowNo == rowNo || isReadBreak ;
    374        }
    375
    376        /**
    377         * 行の終了時に実行されます。
    378         *
    379         * ここでは、rowNo がﾌﾞﾚｰｸするか、ｼｰﾄ終了時に呼ぶことで、
    380         * 一番最後の行の処理を行います。
    381         *
    382         * #NAME 処理中の場合(isNowName == true) は、ｶﾗﾑ名配列を作成して、
    383         * columnNames ｲﾍﾞﾝﾄを呼び出します。
    384         * 値配列が設定されている場合(useVals == true) は、values ｲﾍﾞﾝﾄを
    385         * 呼び出します。
    386         * #NAME 処理が完了している場合は、値配列の初期化を行います。
    387         * そのうえで、ｽｷｯﾌﾟの解除(isColSkip = false)と行ﾃﾞｰﾀ
    388         * 未設定(useVals = false)に、初期化します。
    389         *
    390         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    391         * @og.rev 6.2.2.0 (2015/03/27) Overflow処理は、Tag側に戻す。
    392         * @og.rev 6.3.9.0 (2015/11/06) ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで利用している(findbugs)
    393         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのｵﾘｼﾞﾅﾙを取得できるようにします。
    394         *
    395         * @see #columnNames( String[] )
    396         * @see #values( String[],int )
    397         */
    398        private void endRow() {
    399                if( isNowName ) {                                                                       // #NAME 処理中の場合
    400                        if( clmSize > 0 ) {                                                             // 7.3.1.3 (2021/03/09) names,#NAME が設定済みという意味
    401                                isNowName = false;
    402                                return;
    403                        }
    404
    405                        // 6.3.9.0 (2015/11/06) ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで利用している(findbugs)
    406                        if( colList == null ) {
    407                                final String errMsg = "#value(String,int,char) または#value(String,int,int) を先に実行しておいてください。" ;
    408                                throw new OgRuntimeException( errMsg );
    409                        }
    410
    411                        clmSize = colList.size();
    412                        names   = nmsList.toArray( new String[clmSize] );
    413                        colms   = colList.stream().mapToInt(i->i).toArray();    // 7.3.1.3 (2021/03/09)
    414
    415                        if( nullBreakClm != null ) {
    416                                for( int i=0; i<clmSize; i++ ) {
    417                                        if( nullBreakClm.equalsIgnoreCase( names[i] ) ) {
    418                                                nBrkClmNo = i;
    419                                                break;
    420                                        }
    421                                }
    422                        }
    423                        // 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
    424                        if( nullSkipClm != null ) {
    425                                for( int i=0; i<clmSize; i++ ) {
    426                                        if( nullSkipClm.equalsIgnoreCase( names[i] ) ) {
    427                                                nSkpClmNo = i;
    428                                                break;
    429                                        }
    430                                }
    431                        }
    432
    433                        if( cnstData != null ) { cnstData.setColumns( names ); }
    434                        columnNames( names.clone() );                                                                           // ｲﾍﾞﾝﾄ(setNames でも、#NAME でもｲﾍﾞﾝﾄが発生する)
    435                        isNowName = false;
    436                        colList   = null ;                                                                                                      // 7.3.1.3 (2021/03/09) 不要
    437                        nmsList   = null ;                                                                                                      // 不要
    438                }
    439                else if( useVals ) {                                                                                                    // 値配列が設定されている場合
    440                        if( nBrkClmNo >= 0 && StringUtil.isNull( vals[nBrkClmNo] ) ) {          // nullBreakClm 処理
    441                                isReadBreak = true;                                                                                             // ReadBreak する
    442                        }
    443                        else {
    444                                if( cnstData != null ) { vals = cnstData.getConstVals( vals ); }
    445                                values( vals , nowRowNo );                                                                              // ｲﾍﾞﾝﾄ発行(現在行)
    446                        }
    447                }
    448
    449                if( clmSize > 0 ) {                                                                                                             // clmSize > 0 は、#NAME が設定済みという意味
    450                        vals = new String[clmSize];                                                                                     // 値配列の初期化
    451                }
    452
    453                isColSkip = false;                                                                                                              // ｽｷｯﾌﾟの解除
    454                useVals   = false;                                                                                                              // 行ﾃﾞｰﾀ未設定にする
    455        }
    456
    457        /**
    458         * ｼｰﾄ数のｲﾍﾞﾝﾄが発生します。
    459         *
    460         * ※ EXCEL関係以外の読み取りでは、このｲﾍﾞﾝﾄは発生しません。
    461         *
    462         * 処理の開始前に、ｼｰﾄ数のｲﾍﾞﾝﾄが発生します。
    463         * これを元に、処理するｼｰﾄ番号の選別が可能です。
    464         *
    465         * @og.rev 6.1.0.0 (2014/12/26) ｼｰﾄの数のｲﾍﾞﾝﾄ
    466         *
    467         * @param       size    ｼｰﾄ数
    468         */
    469        public void sheetSize( final int size ) {
    470                if( useDebug ) { System.out.println( "sheetSize=[" + size + "]" ); }
    471        }
    472
    473        /**
    474         * ｶﾗﾑ名配列がそろった段階で、ｲﾍﾞﾝﾄが発生します。
    475         *
    476         * openGion での標準的な処理は、colNo==0 の時に、val の先頭が、#NAME
    477         * で始まるﾚｺｰﾄﾞを、名前配列として認識します。
    478         * #value( String,int,int ) で、この #NAME だけは、継続処理されます。
    479         * その上で、#NAME ﾚｺｰﾄﾞが終了した時点で、ｶﾗﾑ名配列が完成するので
    480         * そこで初めて、このﾒｿｯﾄﾞが呼ばれます。(EXCEL関係の場合)
    481         *
    482         * 外部から設定する、#setNames( String , boolean ) 時も同様に呼ばれます。
    483         *
    484         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    485         *
    486         * @param       names   ｶﾗﾑ名配列
    487         * @see         #value( String,int,int )
    488         * @see         #setNames( String , boolean )
    489         */
    490        public void columnNames( final String[] names ) {
    491                if( useDebug ) { System.out.println( "columnNames=[" + Arrays.toString(names) + "]" ); }
    492        }
    493
    494        /**
    495         * #NAME のｵﾘｼﾞﾅﾙｶﾗﾑ名配列がそろった段階で、ｲﾍﾞﾝﾄが発生します。
    496         *
    497         * #columnNames( String[] ) は、setNames指定時も、#NAME 指定時もｲﾍﾞﾝﾄが発生します。
    498         * このﾒｿｯﾄﾞは、setNames の設定に関係なく、ﾌｧｲﾙに書かれていた #NAME で始まるﾚｺｰﾄﾞを、
    499         * 名前配列として識別して呼出します。
    500         *
    501         * #NAME が存在しない場合は、呼び出されません。
    502         *
    503         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのｵﾘｼﾞﾅﾙを取得できるようにします。
    504         *
    505         * @param       names   #NAME のｵﾘｼﾞﾅﾙｶﾗﾑ名配列
    506         * @see         #columnNames( String[] )
    507         */
    508        public void originalNames( final String[] names ) {
    509                if( useDebug ) { System.out.println( "originalNames=[" + Arrays.toString(names) + "]" ); }
    510        }
    511
    512        /**
    513         * row にあるｾﾙのｵﾌﾞｼﾞｪｸﾄ値がそろった段階で、ｲﾍﾞﾝﾄが発生します。
    514         *
    515         * 初期実装は、何もありません。
    516         *
    517         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
    518         *
    519         * @param       vals    文字列値の1行分の配列
    520         * @param       rowNo   行番号(0～)
    521         */
    522        public void values( final String[] vals,final int rowNo ) {
    523                if( useDebug ) { System.out.println( "values[" + rowNo + "]=[" + Arrays.toString(vals) + "]" ); }
    524        }
    525
    526        /**
    527         * 外部からCSV形式のｶﾗﾑ名文字列を設定します。
    528         *
    529         * ※ ｲﾍﾞﾝﾄ処理実行前の初期化処理です。
    530         *
    531         * ｶﾗﾑ名配列を、#NAME で始まるﾚｺｰﾄﾞではなく、外部から指定します。
    532         * ここで設定した場合、#columnNames( String[] )ｲﾍﾞﾝﾄも発生します。
    533         * null か、長さｾﾞﾛのｶﾗﾑ名は、設定されません。
    534         *
    535         * @og.rev 6.1.0.0 (2014/12/26) ｶﾗﾑ名配列設定の対応
    536         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのｵﾘｼﾞﾅﾙを取得できるようにします。
    537         *
    538         * @param       clms            CSV形式のｶﾗﾑ名文字列
    539         * @param       useNumber       行番号情報 [true:使用している/false:していない]
    540         * @see         #columnNames( String[] )
    541         */
    542        public final void setNames( final String clms , final boolean useNumber ) {
    543                if( clms != null && clms.length() > 0 ) {
    544                        if( useDebug ) { System.out.println( "setNames=[" + clms + "]" ); }
    545
    546                        colList = new ArrayList<>() ;                                                                           // 初期化
    547                        nmsList = new ArrayList<>() ;                                                                           // 初期化
    548
    549                        final String[] nms = StringUtil.csv2Array( clms );
    550                        final int adrs = useNumber ? 1:0 ;                                                                      // useNumber =true の場合は、1件目(No)は読み飛ばす。
    551                        for( int i=0; i<nms.length; i++ ) {
    552                                // null か、長さｾﾞﾛのｶﾗﾑ名は、設定されません。
    553                                final String nm = nms[i];
    554                                if( nm != null && nm.length() > 0 ) {
    555                                        colList.add( Integer.valueOf( i+adrs ) );
    556                                        nmsList.add( nm );
    557                                }
    558                        }
    559                        isNowName = true;                                                                                                       // 名前設定中
    560                        useVals   = false;                                                                                                      // ﾃﾞｰﾀ未設定
    561                        endRow();                                                                                                                       // 行末処理実行。名前設定処理が走ります。
    562                }
    563        }
    564
    565        /**
    566         * ｶﾗﾑ名配列が、設定されたかどうか、返します。
    567         *
    568         * ｶﾗﾑ名配列は、#NAME で始まるﾚｺｰﾄﾞか、#setNames( String,boolean )ﾒｿｯﾄﾞを
    569         * 使用して、外部から指定します。
    570         * ｶﾗﾑ名配列が未設定の場合は、ﾃﾞｰﾀもｾｯﾄできないので、処理の最後の判定に使います。
    571         *
    572         * @og.rev 6.1.0.0 (2014/12/26) ｶﾗﾑ名配列設定の対応
    573         *
    574         * @return      ｶﾗﾑ名配列が、設定されたかどうか(true:設定済み/false:未設定)
    575         * @see         #setNames( String,boolean )
    576         */
    577        public boolean isNameSet() {
    578                // clmSize > 0 は、#NAME が設定済みという意味
    579                return clmSize > 0;
    580        }
    581
    582        /**
    583         * 以降のﾃﾞｰﾀを読み飛ばすかどうかを指定します(初期値:false)。
    584         *
    585         * ﾃﾞｰﾀを読み込む途中で、それ以降のﾃﾞｰﾀを読み込む必要がなくなった場合に、
    586         * true に設定すると、以降のﾃﾞｰﾀを今のｼｰﾄ/ﾌｧｲﾙが終了するまで、ｽｷｯﾌﾟします。
    587         * 例えば、読み込むべき必須ｶﾗﾑで判定する、nullBreakClm 機能を実現できます。
    588         * 初期値は、false:読み飛ばさない です。
    589         *
    590         * @og.rev 6.1.0.0 (2014/12/26) ｼｰﾄﾌﾞﾚｲｸ処理追加
    591         *
    592         * @param       flag    以降のﾃﾞｰﾀを読み飛ばすかどうか [true:読み飛ばす/false:読み飛ばさない]
    593         * @see         #isSkip( int )
    594         */
    595        public void setReadBreak( final boolean flag ) {
    596                isReadBreak = flag ;
    597        }
    598
    599        /**
    600         * 先頭ﾃﾞｰﾀの読み飛ばし件数を設定します。
    601         *
    602         * ※ ｲﾍﾞﾝﾄ処理実行前の初期化処理です。
    603         *
    604         * ﾃﾞｰﾀの読み始めの行を指定します。
    605         * ｼｰﾄ/ﾌｧｲﾙの先頭行が、0行としてｶｳﾝﾄしますので、設定値は、読み飛ばす
    606         * 件数になります。(1と指定すると、1件読み飛ばし、２件目から読み込みます。)
    607         * 読み飛ばしは、ｺﾒﾝﾄ行などは、無視しますので、実際の行数分読み飛ばします。
    608         * ＃NAME属性や、columns 属性は、読み飛ばし中でも処理対象行になります。
    609         *
    610         * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
    611         *
    612         * @param       count   読み始めの初期値(0なら、読み飛ばしなし)
    613         */
    614        public void setSkipRowCount( final int count ) {
    615                skipRowCnt = count;
    616        }
    617
    618        /**
    619         * ここに指定されたｶﾗﾑ列に NULL/ｾﾞﾛ文字列 が現れた時点でSheetの読み取りを中止します。
    620         *
    621         * これは、指定のｶﾗﾑは必須という事を条件に、そのﾚｺｰﾄﾞだけを読み取る処理を行います。
    622         * 複数Sheetの場合は、次のSheetを読みます。
    623         * Sheetが存在しない場合(通常のﾃｷｽﾄ等)では、読み取り処理の終了になります。
    624         *
    625         * @og.rev 6.2.0.0 (2015/02/27) 新規追加
    626         *
    627         * @param       clm     ｶﾗﾑ列
    628         */
    629        public void setNullBreakClm( final String clm ) {
    630                nullBreakClm = clm;
    631        }
    632
    633        /**
    634         * ここに指定されたｶﾗﾑ列に NULL が現れたﾚｺｰﾄﾞは読み飛ばします。
    635         *
    636         * 例えば、更新対象ｶﾗﾑで、null の場合は、何もしない、などのｹｰｽで使用できます。
    637         * 複数ｶﾗﾑの場合は、AND条件やOR条件などが、考えられるため、
    638         * ｶﾗﾑを一つにまとめて、指定してください。
    639         *
    640         * @og.rev 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
    641         *
    642         * @param       clm     ｶﾗﾑ列
    643         */
    644        public void setNullSkipClm( final String clm ) {
    645                nullSkipClm = clm;
    646        }
    647
    648        /**
    649         * 固定値となるｶﾗﾑ名(CSV形式)と、固定値となるｱﾄﾞﾚｽ(行-列,行-列...) or(A1,B3...)を設定します。
    650         *
    651         * ※ ｲﾍﾞﾝﾄ処理実行前の初期化処理です。
    652         *
    653         * ｱﾄﾞﾚｽは、EXCEL上の行-列か、EXCEL列のA1,B3 などの形式を、CSV形式で指定します。
    654         * 行列は、EXCELｵﾌﾞｼﾞｪｸﾄに準拠するため、0から始まる整数です。
    655         * 0-0 ⇒ A1 , 1-0 ⇒ A2 , 0-1 ⇒ B1 になります。
    656         * これにより、ｼｰﾄの一か所に書かれている情報を、DBTableModel のｶﾗﾑに固定値として
    657         * 設定することができます。
    658         * 例として、DB定義書で、ﾃｰﾌﾞﾙ名をｼｰﾄの全ﾚｺｰﾄﾞに設定したい場合などに使います。
    659         *
    660         * 5.7.6.3 (2014/05/23) より、
    661         *   ①EXCEL表記に準拠した、A1,A2,B1 の記述も処理できるように対応します。
    662         *     なお、A1,A2,B1 の記述は、必ず、英字1文字＋数字 にしてください。(A～Zまで)
    663         *     EXCEL2007形式で列数が拡張されていますが、列数は制限しています。
    664         *   ②処理中のEXCELｼｰﾄ名をｶﾗﾑに割り当てるために、"SHEET" という記号に対応します。
    665         * 6.2.0.0 (2015/02/27) より、
    666         *   ③EXCEL以外では、"FILE","NAME","SUFIX" が使えます。(EXCEL時にも使えます。)
    667         *     NAME は、ﾌｧｲﾙ名から拡張子を取り除いた文字列になります。(AAA/BBB/CCC.xls → CCC)
    668         * 例えば、sheetConstKeys="CLM,LANG,NAME" とし、sheetConstAdrs="0-0,A2,SHEET" とすると、
    669         * NAMEｶﾗﾑには、ｼｰﾄ名を読み込むことができます。
    670         * これは、内部処理の簡素化のためです。
    671         *
    672         * ちなみに、EXCELのｾﾙに、ｼｰﾄ名を表示させる場合の関数は、下記の様になります。
    673         * =RIGHT(CELL("filename",$A$1),LEN(CELL("filename",$A$1))-FIND("]",CELL("filename",$A$1)))
    674         *
    675         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
    676         * @og.rev 5.7.6.3 (2014/05/23) EXCEL表記(A2,B1等)の対応と、特殊記号(SHEET)の対応
    677         * @og.rev 6.1.0.0 (2014/12/26) ｶﾗﾑ名配列設定の対応
    678         *
    679         * @param       constKeys       固定値となるｶﾗﾑ名(CSV形式)
    680         * @param       constAdrs       固定値となるｱﾄﾞﾚｽ(行-列,行-列...) or(A1,B3...)
    681         */
    682        public void setConstData( final String constKeys,final String constAdrs ) {
    683                if( constKeys != null && !constKeys.isEmpty() && constAdrs != null && !constAdrs.isEmpty() ) {
    684                        cnstData = new ConstData( constKeys,constAdrs );
    685                        // setNames( String , boolean ) と、このﾒｿｯﾄﾞの呼び出し順に影響がないようにするため。
    686                        if( names != null ) { cnstData.setColumns( names ); }
    687                }
    688        }
    689
    690        /**
    691         * ﾃﾞﾊﾞｯｸﾞ情報を出力するかどうか[true:する/false:しない]を指定します。
    692         *
    693         * EXCELなどを読み取る場合、ｼｰﾄﾏｰｼﾞで読み取ると、ｴﾗｰ時の行番号が、連番になるため、
    694         * どのｼｰﾄなのか、判らなくなります。
    695         * そこで、どうしてもわからなくなった場合に備えて、ﾃﾞﾊﾞｯｸﾞ情報を出力できるようにします。
    696         * 通常は使用しませんので、設定を無視します。
    697         * 初期値は、false:ﾃﾞﾊﾞｯｸﾞ情報を出力しない です。
    698         *
    699         * @og.rev 6.2.0.0 (2015/02/27) ﾃﾞﾊﾞｯｸﾞ情報の出力するかどうか。新規追加
    700         *
    701         * @param       useDebug        ﾃﾞﾊﾞｯｸﾞ出力するか [true:する/false:しない]
    702         */
    703        public void setDebug( final boolean useDebug ) {
    704                this.useDebug = useDebug;
    705        }
    706
    707        /**
    708         * ﾃﾞﾊﾞｯｸﾞ情報を出力するかどうか[true:する/false:しない]を取得します。
    709         *
    710         * EXCELなどを読み取る場合、ｼｰﾄﾏｰｼﾞで読み取ると、ｴﾗｰ時の行番号が、連番になるため、
    711         * どのｼｰﾄなのか、判らなくなります。
    712         * そこで、どうしてもわからなくなった場合に備えて、ﾃﾞﾊﾞｯｸﾞ情報を出力できるようにします。
    713         *
    714         * @og.rev 6.2.0.0 (2015/02/27) ﾃﾞﾊﾞｯｸﾞ情報の出力するかどうか。新規追加
    715         *
    716         * @return      ﾃﾞﾊﾞｯｸﾞ出力 [true:する/false:しない]
    717         */
    718        protected boolean isDebug() {
    719                return useDebug ;
    720        }
    721
    722        /**
    723         * EXCELﾌｧｲﾙの所定の位置から、固定値を取り出す処理を管理します。
    724         *
    725         * この固定値の取出しは、内部処理に、非常に依存しているため、今は、
    726         * TableModelHelper ｸﾗｽに含めていますが、将来的には、分ける予定です。
    727         *
    728         * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
    729         * @og.rev 6.2.0.0 (2015/02/27) 特殊記号(FILE,NAME,SUFIX)追加
    730         *
    731         * @version     6.0
    732         * @author      Kazuhiko Hasegawa
    733         * @since       JDK7.0,
    734         */
    735        private static final class ConstData {
    736                /** 内部情報のｸﾘｱ方法の指定 {@value} */
    737                public static final int END_FILE  = 1 ;
    738                /** 内部情報のｸﾘｱ方法の指定 {@value} */
    739                public static final int END_SHEET = 2 ;
    740
    741                // 6.2.0.0 (2015/02/27) 特殊記号処理 追加 (SHEET,FILE,NAME,SUFIX)
    742                private static final String KEYS = ",SHEET,FILE,NAME,SUFIX,";
    743
    744                // ①cnstMap は、cnstKey をｷｰに、拾ってきた値を持っています。(Sheet毎のﾄﾗﾝｻﾞｸｼｮﾝ)
    745                private final Map<String,String> cnstMap = new HashMap<>();                             // 6.1.0.0 (2014/12/26) Mapで管理
    746                // ②rowcolMap は、rowcol をｷｰに、ｱﾄﾞﾚｽを持っています。
    747                private final Map<String,Integer> rowcolMap = new HashMap<>();                  // 6.1.0.0 (2014/12/26) Mapで管理
    748                // ③valsMap は、ｱﾄﾞﾚｽ をｷｰに、拾ってきた値を持っています。(Sheet毎のﾄﾗﾝｻﾞｸｼｮﾝ)
    749                private final Map<Integer,String> valsMap = new HashMap<>();                    // 6.1.0.0 (2014/12/26) Mapで管理
    750
    751                private final int maxRow  ;             // 6.4.9.1 (2016/08/05) final化。最大値持っておき、判定処理を早める。
    752
    753                // ※ rowcolMap を使用する為、必ず #setColumns( String... ) の実行後に行います。
    754                private boolean isNameSet ;
    755                private File    tmpFile   ;
    756                private String  tmpShtNm  ;
    757
    758                /**
    759                 * 固定値となるｶﾗﾑ名(CSV形式)と、固定値となるｱﾄﾞﾚｽ(行-列,行-列...) or(A1,B3...)を設定します。
    760                 *
    761                 * ｱﾄﾞﾚｽは、EXCEL上の行-列か、EXCEL列のA1,B3 などの形式を、CSV形式で指定します。
    762                 * 行列は、EXCELｵﾌﾞｼﾞｪｸﾄに準拠するため、0から始まる整数です。
    763                 * 0-0 ⇒ A1 , 1-0 ⇒ A2 , 0-1 ⇒ B1 になります。
    764                 * これにより、ｼｰﾄの一か所に書かれている情報を、DBTableModel のｶﾗﾑに固定値として
    765                 * 設定することができます。
    766                 * 例として、DB定義書で、ﾃｰﾌﾞﾙ名をｼｰﾄの全ﾚｺｰﾄﾞに設定したい場合などに使います。
    767                 *
    768                 * 5.7.6.3 (2014/05/23) より、
    769                 *   ①EXCEL表記に準拠した、A1,A2,B1 の記述も処理できるように対応します。
    770                 *     なお、A1,A2,B1 の記述は、必ず、英字1文字＋数字 にしてください。(A～Zまで)
    771                 *     EXCEL2007形式で列数が拡張されていますが、列数は制限しています。
    772                 *   ②処理中のEXCELｼｰﾄ名をｶﾗﾑに割り当てるために、"SHEET" という記号に対応します。
    773                 * 6.2.0.0 (2015/02/27) より、
    774                 *   ③EXCEL以外では、"FILE","NAME","SUFIX" が使えます。
    775                 *     NAME は、ﾌｧｲﾙ名から拡張子を取り除いた文字列になります。(AAA/BBB/CCC.xls → CCC)
    776                 * 例えば、sheetConstKeys="CLM,LANG,SHT" とし、sheetConstAdrs="0-0,A2,SHEET" とすると、
    777                 * SHTｶﾗﾑには、ｼｰﾄ名を読み込むことができます。
    778                 * これは、内部処理の簡素化のためです。
    779                 *
    780                 * ちなみに、EXCELのｾﾙに、ｼｰﾄ名を表示させる場合の関数は、下記の様になります。
    781                 * =RIGHT(CELL("filename",$A$1),LEN(CELL("filename",$A$1))-FIND("]",CELL("filename",$A$1)))
    782                 *
    783                 * @og.rev 5.5.8.2 (2012/11/09) 新規追加
    784                 * @og.rev 5.7.6.3 (2014/05/23) EXCEL表記(A2,B1等)の対応と、特殊記号(SHEET)の対応
    785                 * @og.rev 6.1.0.0 (2014/12/26) ｶﾗﾑ名配列設定の対応
    786                 * @og.rev 6.2.0.0 (2015/02/27) 特殊記号(FILE,NAME,SUFIX)の追加対応
    787                 * @og.rev 6.4.9.1 (2016/08/05) maxRowをfinal化します。
    788                 *
    789                 * @param       constKeys       固定値となるｶﾗﾑ名(CSV形式)
    790                 * @param       constAdrs       固定値となるｱﾄﾞﾚｽ(行-列,行-列...) or(A1,B3...)
    791                 */
    792                ConstData( final String constKeys,final String constAdrs ) {
    793                        final String[] cnstKeys = constKeys.split( "," );
    794                        final String[] row_col  = constAdrs.split( "," );
    795
    796                        if( cnstKeys.length != row_col.length ) {
    797                                final String errMsg = "キーに対するアドレスの個数が不一致です。Keys=[" + constKeys + "]"
    798                                                        + " , Adrs=[" + constAdrs + "]" ;
    799                                throw new OgRuntimeException( errMsg );
    800                        }
    801
    802                        int tmpRow = -1;                                                                                                        // 6.4.9.1 (2016/08/05)
    803                        // 初期の ｶﾗﾑとｱﾄﾞﾚｽ(ｷｰﾜｰﾄﾞ)の関連付け
    804                        for( int j=0; j<cnstKeys.length; j++ ) {
    805                                final String cnstKey = cnstKeys[j].trim();                                              // 前後の不要なｽﾍﾟｰｽを削除
    806                                if( !cnstKey.isEmpty() ) {
    807                                        String rowcol = row_col[j].trim();                                                      // 前後の不要なｽﾍﾟｰｽを削除
    808                                        if( !rowcol.isEmpty() ) {
    809                                                // 5.7.6.3 (2014/05/23) EXCEL表記(A2,B1等)の対応と、特殊記号(SHEET)の対応
    810                                                final int sep = rowcol.indexOf( '-' );
    811                                                if( sep > 0 ) {
    812                                                        final int row = Integer.parseInt( rowcol.substring( 0,sep ) );
    813                        //                              int col = Integer.parseInt( rowcol.substring( sep+1 ) );
    814                                                        if( tmpRow < row ) { tmpRow = row; }                            // 6.4.9.1 (2016/08/05)
    815                        //                              rowcol = String.valueOf( (char)('A' + col) ) + String.valueOf( row + 1 ) ;      // row-col 形式なので、不要
    816                                                }
    817                                                // 6.2.0.0 (2015/02/27) 特殊記号(SHEET,FILE,NAME,SUFIX)の追加対応
    818                                                else if( !KEYS.contains( ',' + rowcol + ',' ) ) {
    819                                                        final int row = Integer.parseInt( rowcol.substring( 1 ) ) -1;   // C6 の場合、rowは、6-1=5
    820                                                        final int col = rowcol.charAt(0) - 'A' ;                                                // C6 の場合、colは、'C'-'A'=2
    821                                                        if( tmpRow < row ) { tmpRow = row; }                            // 6.4.9.1 (2016/08/05)
    822                                                        rowcol = row + "-" + col ;
    823                                                }
    824                                                cnstMap.put( cnstKey , rowcol );                                                // 6.1.0.0 (2014/12/26) cnstMap に行列情報を設定する
    825                                        }
    826                                }
    827                        }
    828                        maxRow = tmpRow;
    829                }
    830
    831                /**
    832                 * ｶﾗﾑ名配列を元に、固定値ｶﾗﾑのｱﾄﾞﾚｽを求めます。
    833                 * ｶﾗﾑ名配列は、順番に、指定する必要があります。
    834                 *
    835                 * @og.rev 6.1.0.0 (2014/12/26) ｶﾗﾑ名配列設定の対応
    836                 *
    837                 * @param       names   ｶﾗﾑ列配列(可変長引数)
    838                 */
    839                /* default */ void setColumns( final String... names ) {
    840                        // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    841                        if( names != null && names.length > 0 ) {
    842                                // 5.5.8.2 (2012/11/09) 固定値取得用の cnstIndx の設定を行う。
    843                                for( int i=0; i<names.length; i++ ) {
    844                                        final String rowcol = cnstMap.get( names[i] );          // cnstKey があれば、rowcol が取得できるはず
    845                                        if( rowcol != null ) {
    846                                                rowcolMap.put( rowcol , Integer.valueOf( i ) );
    847                                        }
    848                                }
    849                                isNameSet = true;                       // 名前設定がされないと、FILEやSHEET ｷｰﾜｰﾄﾞが使えない。
    850
    851                                if( tmpFile  != null ) { putConstFile(  tmpFile  ); }
    852                                if( tmpShtNm != null ) { putConstSheet( tmpShtNm ); }
    853                        }
    854                }
    855
    856                /**
    857                 * 読み取り時に、rowNo,colNo にあるｾﾙの値を、固定値となるｶﾗﾑ名に関連付けます。
    858                 *
    859                 * ｲﾍﾞﾝﾄﾓﾃﾞﾙでは、固定値の指定ｱﾄﾞﾚｽ(rowNo,colNo)をﾋﾟﾝﾎﾟｲﾝﾄで取得することが
    860                 * できないため、ｲﾍﾞﾝﾄ発生毎に、ﾁｪｯｸする必要があります。
    861                 * そのため、固定値を使用すると、処理速度が低下します。
    862                 *
    863                 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
    864                 *
    865                 * @param       val             文字列値(null またはｾﾞﾛ文字列は、不可)
    866                 * @param       rowNo   行番号(0～)
    867                 * @param       colNo   列番号(0～)
    868                 */
    869                /* default */ void putConstValue( final String val,final int rowNo,final int colNo ) {
    870                        if( rowNo <= maxRow ) {
    871                                final String rowcol = rowNo + "-" + colNo ;
    872                                final Integer adrs = rowcolMap.get( rowcol );
    873                                if( adrs != null ) {
    874                                        valsMap.put( adrs,val );
    875                                }
    876                        }
    877                }
    878
    879                /**
    880                 * ﾌｧｲﾙ系特殊記号(FILE,NAME,SUFIX)を指定します。
    881                 *
    882                 * ../AAA/BBB/CCC.XLS というﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄに対して、
    883                 *   FILE    : CCC.XLS ﾌｧｲﾙ名
    884                 *   NAME    : CCC     拡張子なしのﾌｧｲﾙ名
    885                 *   SUFIX   : xls     ﾋﾟﾘｵﾄﾞ無しの拡張子(小文字に統一)
    886                 *
    887                 * これは、新しいﾌｧｲﾙの読み取り開始時に、設定します。
    888                 *
    889                 * ※ rowcolMap を使用する為、必ず #setColumns( String... ) の実行後に行います。
    890                 *
    891                 * @og.rev 6.2.0.0 (2015/02/27) 新規作成
    892                 *
    893                 * @param       filNm   指定ﾌｧｲﾙ
    894                 */
    895                /* default */ void putConstFile( final File filNm ) {
    896                        if( filNm != null ) {
    897                                tmpFile = filNm;                // 名前設定がされるまで、一時保管する。(順番があるので呼ばれればｾｯﾄしておく)
    898                                if( isNameSet ) {               // 名前設定がされないと、FILEやSHEET ｷｰﾜｰﾄﾞが使えない。
    899                                        final FileInfo info = new FileInfo( filNm );
    900
    901                                        for( final String key : FileInfo.KEY_LIST ) {
    902                                                final Integer adrs = rowcolMap.get( key );
    903                                                if( adrs != null ) {
    904                                                        final String val = info.getValue( key );
    905                                                        if( val != null ) {
    906                                                                valsMap.put( adrs,val );
    907                                                        }
    908                                                }
    909                                        }
    910                                }
    911                        }
    912                }
    913
    914                /**
    915                 * ｼｰﾄ名を外部から指定します。
    916                 * ｱﾄﾞﾚｽ指定の特殊系として、"SHEET" 文字列を指定できます。
    917                 * これは、新しいｼｰﾄの読み取り開始時に、設定します。
    918                 *
    919                 * ※ rowcolMap を使用する為、必ず #setColumns( String... ) の実行後に行います。
    920                 *
    921                 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
    922                 *
    923                 * @param       shtNm   ｼｰﾄ名
    924                 */
    925                /* default */ void putConstSheet( final String shtNm ) {
    926                        if( shtNm != null ) {
    927                                tmpShtNm = shtNm;               // 名前設定がされるまで、一時保管する。
    928                                if( isNameSet ) {               // 名前設定がされないと、FILEやSHEET ｷｰﾜｰﾄﾞが使えない。
    929                                        final Integer adrs = rowcolMap.get( "SHEET" );
    930                                        if( adrs != null ) {
    931                                                valsMap.put( adrs,shtNm );
    932                                        }
    933                                }
    934                        }
    935                }
    936
    937                /**
    938                 * 内部の valsMap を初期化します。
    939                 * 固定値の読み取りは、ｼｰﾄごとに行います。
    940                 * 新しいｼｰﾄにﾃﾞｰﾀが設定されていない場合、前のｼｰﾄの値が残ります。
    941                 * ここでは、ｼｰﾄ呼出しごとに、毎回ｸﾘｱします。
    942                 * 引数に応じて、ｸﾘｱする範囲を限定します。
    943                 * END_FILE 時は、すべてｸﾘｱ。END_SHEET 時は、ﾌｧｲﾙ情報は残します。
    944                 *
    945                 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
    946                 *
    947                 * @param       type    内部情報のｸﾘｱ方法の指定(END_FILE or END_SHEET)
    948                 */
    949                /* default */ void clearValsMap( final int type ) {
    950                        valsMap.clear();
    951                        if( type == END_SHEET ) { putConstFile( tmpFile ); }    // 全削除後にﾌｧｲﾙ情報を再設定
    952                }
    953
    954                /**
    955                 * 値配列のﾃﾞｰﾀに、固定値を設定します。
    956                 * 引数の文字列配列に、固定値を設定しますので、配列ｵﾌﾞｼﾞｪｸﾄ自体を更新します。
    957                 *
    958                 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
    959                 * @og.rev 6.4.3.4 (2016/03/11) forﾙｰﾌﾟを、forEach ﾒｿｯﾄﾞに置き換えます。
    960                 *
    961                 * @param       vals    文字列値の1行分の配列
    962                 * @return      固定値を設定された1行分の文字列配列
    963                 */
    964                /* default */ String[] getConstVals( final String[] vals ) {
    965                        if( vals != null && vals.length > 0 ) {
    966                                // 6.4.3.4 (2016/03/11) forﾙｰﾌﾟを、forEach ﾒｿｯﾄﾞに置き換えます。
    967                                valsMap.forEach( (k,v) -> {
    968                                                        if( k < vals.length ) { vals[k] = v; }
    969                                } );
    970                        }
    971                        return vals ;
    972                }
    973        }
    974}