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 java.util.List;
019import java.util.ArrayList;
020import java.util.Map;                                                                                                                   // 6.1.0.0 (2014/12/26) ConstData を Mapで管理
021import java.util.HashMap;                                                                                                               // 6.1.0.0 (2014/12/26) ConstData を Mapで管理
022import java.util.Arrays;                                                                                                                // 6.2.0.0 (2015/02/27)
023import java.io.File;                                                                                                                    // 6.2.0.0 (2015/02/27)
024
025import org.opengion.fukurou.system.OgRuntimeException;                                                  // 6.4.2.0 (2016/01/29)
026import org.opengion.fukurou.util.StringUtil;                                                                    // 6.2.0.0 (2015/02/27)
027import org.opengion.fukurou.util.FileInfo;                                                                              // 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                                                        // 2.0.0 (2024/01/12) PMD 7.0.0 UnnecessaryBoxing
217//                                                      colList.add( Integer.valueOf( colNo ) );
218                                                        colList.add( colNo );
219                                                        nmsList.add( nm );
220                                                }
221                                        }
222//                                      originalNames( nmsList.toArray( new String[nmsList.size()] ) ); // 7.3.1.3 (2021/03/09) #NAMEのオリジナルを取得
223                                        originalNames( nmsList.toArray( new String[0] ) );      // 7.3.1.3 (2021/03/09) #NAMEのオリジナルを取得 // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
224                                        isNowName = true;
225                                }
226                        }
227                        // clmSize > 0 は、#NAME が設定済みという意味
228                        else if( clmSize > 0 && skipRowCnt <= rowNo ) {                                         // skipRowCnt は、値セットだけ影響する。
229                                final String[] tmpVals = StringUtil.csv2Array( line ,sepa );
230        //                      if( cnstData != null ) { tmpVals = cnstData.getConstVals( tmpVals ); }
231        //                      int min = Math.min( clmSize,tmpVals.length );
232
233                //              // 8.4.0.0 (2022/12/23) 7.1.0.0 (2020/01/27) の対応は、ReadTableTag に移動。
234                //              // 7.1.0.0 (2020/01/27) エンコードによってはエラーにならず1カラムのデータとして取れてしまう。
235                //              // カラム数が1以上で、データ数が1の場合は、取り込みミスなので処理を終了する。
236                //              if( clmSize > 1 && tmpVals.length == 1 ) {
237                //                      isReadBreak = true;                                                                                     // 処理の停止
238                //                      clmSize     = 0;                                                                                        // #NAME列未設定と同じ(-1にしないのは、単に初期値と違うという事)
239                //                      return ;                                                                                                        // 即抜ける
240                //              }
241
242                                for( int i=0; i<clmSize; i++ ) {
243//                                      final int indx = colList.get( i );                                                      // カラム番号の位置が 値配列の配列番号
244                                        final int indx = colms[i];                                                                      // 7.3.1.3 (2021/03/09) カラム番号の位置が 値配列の配列番号
245                                        if( indx >= 0 && indx < tmpVals.length ) {
246                                                vals[i] = StringUtil.csvOutQuote( tmpVals[indx] );              // 6.2.1.0 (2015/03/13)
247                                        }
248                                }
249                                useVals = true;
250        //                      values( vals , rowNo );                                                                                 // イベント発行(現在行)
251                        }
252
253                        endRow();                                                                                                                       // 行末処理実行。名前設定処理が走ります。
254                }
255        }
256
257        /**
258         * 読み取り状態の時に、rowNo,colNo にあるセルの値を引数にイベントが発生します。
259         *
260         * ※ 主に、EXCEL関係の読み取り処理で使用されるメソッドです。
261         *    このメソッドは、EventReader#eventReader( String , TableModelHelper )メソッドの
262         *    処理の過程で、設定されます。
263         *    このメソッドから、各種イベントが発行されます。
264         *
265         * 戻り値が、true の場合は、その行の読み取りを継続します。
266         * false の場合は、その行の読み取りは行わず、次の行まで
267         * イベントは発行されません。
268         *
269         * openGion での標準的な処理は、colNo==0 の時に、val の先頭が、# で
270         * 始まる場合は、その行はスキップします。
271         * ここでの return は、#isSkip( int ) と逆になりますので、ご注意ください。
272         * 初期実装では、#NAME処理、行スキップ、行終了処理等を実行します。
273         * オーバーライドする場合は、super.value(String,int,int) してください。
274         *
275         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
276         * @og.rev 6.2.2.0 (2015/03/27) 先頭に、'0 が含まれる場合のセミコロンや、前後のダブルクオートは削除
277         * @og.rev 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
278         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのオリジナルを取得できるようにします。
279         *
280         * @param       val             文字列値
281         * @param       rowNo   行番号(0~)
282         * @param       colNo   列番号(0~)
283         * @return      読み取りするかどうか(true:読み取りする/false:読み取りしない)
284         * @see         #isSkip( int )
285         */
286        protected boolean value( final String val,final int rowNo,final int colNo ) {
287        //      if( useDebug ) { System.out.println( "R[" + rowNo + "," + colNo + "]=" + val ); }
288
289                // 値が存在する場合のみ、処理する。
290                if( val!=null && val.length()>0 ) {
291                        // 行番号が異なった場合は、行の終了処理を実行する。
292                        if( nowRowNo != rowNo ) {
293                                if( isNowName ) {                                                                                               // 7.3.1.3 (2021/03/09) #NAMEのオリジナルを取得
294//                                      originalNames( nmsList.toArray( new String[nmsList.size()] ) );
295                                        originalNames( nmsList.toArray( new String[0] ) );      // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
296                                }
297
298                                endRow();                                                                                                               // 行終了処理
299                                nowRowNo = rowNo;                                                                                               // 現在行の設定
300                        }
301
302                        // 固定文字の設定なので、コメントもスキップも無関係
303                        if( cnstData != null ) { cnstData.putConstValue( val,rowNo,colNo ); }
304
305                        // 先頭カラムのコメント判断と、#NAME列判断
306                        if( colNo==0 && val.charAt(0)=='#' ) {
307//                              if( "#NAME".equalsIgnoreCase( val ) && clmSize <= 0 ) {                 // clmSize <= 0 は、#NAME未設定という意味
308                                // 7.3.1.3 (2021/03/09) #NAME があれば処理する
309                                if( "#NAME".equalsIgnoreCase( val )) {
310                                        isNowName = true ;
311                                        colList = new ArrayList<>() ;                                                           // 初期化
312                                        nmsList = new ArrayList<>() ;                                                           // 初期化
313                                }
314                                isColSkip = !isNowName;                                                                                 // #NAME の場合は、false(SKIPしない)
315                        }
316                        // #NAME処理中
317                        else if( isNowName ) {
318                                // #NAME 設定も、null や、ゼロ文字列の場合は、登録しない。(一番上の if で対処)
319                                // 2.0.0 (2024/01/12) PMD 7.0.0 UnnecessaryBoxing
320//                              colList.add( Integer.valueOf( colNo ) );
321                                colList.add( colNo );
322                                nmsList.add( val );
323                        }
324                        // 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
325                        else if( nSkpClmNo >= 0 && StringUtil.isNull( vals[nSkpClmNo] ) ) {     // nullSkipClm 処理
326                                isColSkip = true;       // Skip する
327                        }
328                        // clmSize > 0 は、#NAME が設定済みという意味
329                        // 7.3.1.3 (2021/03/09) カラム番号の位置が 値配列の配列番号
330                        else if( clmSize > 0 && skipRowCnt <= rowNo ) {                                         // skipRowCnt は、値セットだけ影響する
331                                for( int i=0; i<clmSize ; i++ ) {                                                               // カラム番号の位置が 値配列の配列番号
332                                        if( colms[i] == colNo ) {
333                                                vals[i] = StringUtil.csvOutQuote( val );                                // 6.2.2.0 (2015/03/27)
334                                                useVals = true;
335                                                break;
336                                        }
337                                }
338                        }
339//                      else if( clmSize > 0 && skipRowCnt <= rowNo ) {                                         // skipRowCnt は、値セットだけ影響する。
340//                              final int indx = colList.indexOf( Integer.valueOf( colNo ) );   // カラム番号の位置が 値配列の配列番号
341//                              if( indx >= 0 ) {
342//                                      vals[indx] = StringUtil.csvOutQuote( val );                                     // 6.2.2.0 (2015/03/27)
343//                                      useVals = true;
344//                              }
345//                      }
346                }
347
348                return !isColSkip;
349        }
350
351        /**
352         * rowNo を元に、この行をスキップするかどうか判定のイベントが発生します。
353         *
354         * ※ EXCEL関係の列毎にイベントが発生する場合の列処理をスキップするのが目的です。
355         *    行単位に読み込む場合や、行のループに入れても、意味はありません。
356         *    引数から、行のループに入れてしまいそうですが、行列のループに入れてください。
357         *
358         * ※ 主に、EXCEL関係の読み取り処理で使用されるメソッドです。
359         *    このメソッドは、EventReader#eventReader( String , TableModelHelper )メソッドの
360         *    処理の過程で、設定されます。
361         *    このメソッドから、各種イベントが発行されます。
362         *
363         * 戻り値が、true の場合は、その行の読み取りをスキップします。
364         * false の場合は、読み取り処理を継続します。
365         * スキップ中は、行に関するイベントは発行されません。
366         *
367         * 値(val)を求める前に、行情報を入手し、スキップ中の現在行と同じ場合に、スキップ(=true)と判定します。
368         * スキップ中かどうかは、#value( String,int,int ) で、判定します。
369         * 初期実装では、スキップ中 かつ 現在行と同じ行の場合、または、シートブレーク中の場合に、true を返します。
370         *
371         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
372         * @og.rev 6.1.0.0 (2014/12/26) シートブレイク処理追加
373         *
374         * @param       rowNo   行番号(0~)
375         * @return      スキップするかどうか(true:スキップする/false:スキップしない)
376         * @see         #value( String,int,int )
377         */
378        protected boolean isSkip( final int rowNo ) {
379                return isColSkip && nowRowNo == rowNo || isReadBreak ;
380        }
381
382        /**
383         * 行の終了時に実行されます。
384         *
385         * ここでは、rowNo がブレークするか、シート終了時に呼ぶことで、
386         * 一番最後の行の処理を行います。
387         *
388         * #NAME 処理中の場合(isNowName == true) は、カラム名配列を作成して、
389         * columnNames イベントを呼び出します。
390         * 値配列が設定されている場合(useVals == true) は、values イベントを
391         * 呼び出します。
392         * #NAME 処理が完了している場合は、値配列の初期化を行います。
393         * そのうえで、スキップの解除(isColSkip = false)と行データ
394         * 未設定(useVals = false)に、初期化します。
395         *
396         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
397         * @og.rev 6.2.2.0 (2015/03/27) Overflow処理は、Tag側に戻す。
398         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
399         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのオリジナルを取得できるようにします。
400         *
401         * @see #columnNames( String[] )
402         * @see #values( String[],int )
403         */
404        private void endRow() {
405                if( isNowName ) {                                                                       // #NAME 処理中の場合
406                        if( clmSize > 0 ) {                                                             // 7.3.1.3 (2021/03/09) names,#NAME が設定済みという意味
407                                isNowName = false;
408                                return;
409                        }
410
411                        // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
412                        if( colList == null ) {
413                                final String errMsg = "#value(String,int,char) または#value(String,int,int) を先に実行しておいてください。" ;
414                                throw new OgRuntimeException( errMsg );
415                        }
416
417                        clmSize = colList.size();
418//                      names   = nmsList.toArray( new String[clmSize] );
419                        names   = nmsList.toArray( new String[0] );     // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
420                        colms   = colList.stream().mapToInt(i->i).toArray();    // 7.3.1.3 (2021/03/09)
421
422                        if( nullBreakClm != null ) {
423                                for( int i=0; i<clmSize; i++ ) {
424                                        if( nullBreakClm.equalsIgnoreCase( names[i] ) ) {
425                                                nBrkClmNo = i;
426                                                break;
427                                        }
428                                }
429                        }
430                        // 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
431                        if( nullSkipClm != null ) {
432                                for( int i=0; i<clmSize; i++ ) {
433                                        if( nullSkipClm.equalsIgnoreCase( names[i] ) ) {
434                                                nSkpClmNo = i;
435                                                break;
436                                        }
437                                }
438                        }
439
440                        if( cnstData != null ) { cnstData.setColumns( names ); }
441                        columnNames( names.clone() );                                                                           // イベント(setNames でも、#NAME でもイベントが発生する)
442                        isNowName = false;
443                        colList   = null ;                                                                                                      // 7.3.1.3 (2021/03/09) 不要
444                        nmsList   = null ;                                                                                                      // 不要
445                }
446                else if( useVals ) {                                                                                                    // 値配列が設定されている場合
447                        if( nBrkClmNo >= 0 && StringUtil.isNull( vals[nBrkClmNo] ) ) {          // nullBreakClm 処理
448                                isReadBreak = true;                                                                                             // ReadBreak する
449                        }
450                        else {
451                                if( cnstData != null ) { vals = cnstData.getConstVals( vals ); }
452                                values( vals , nowRowNo );                                                                              // イベント発行(現在行)
453                        }
454                }
455
456                if( clmSize > 0 ) {                                                                                                             // clmSize > 0 は、#NAME が設定済みという意味
457                        vals = new String[clmSize];                                                                                     // 値配列の初期化
458                }
459
460                isColSkip = false;                                                                                                              // スキップの解除
461                useVals   = false;                                                                                                              // 行データ未設定にする
462        }
463
464        /**
465         * シート数のイベントが発生します。
466         *
467         * ※ EXCEL関係以外の読み取りでは、このイベントは発生しません。
468         *
469         * 処理の開始前に、シート数のイベントが発生します。
470         * これを元に、処理するシート番号の選別が可能です。
471         *
472         * @og.rev 6.1.0.0 (2014/12/26) シートの数のイベント
473         *
474         * @param       size    シート数
475         */
476        public void sheetSize( final int size ) {
477                if( useDebug ) { System.out.println( "sheetSize=[" + size + "]" ); }
478        }
479
480        /**
481         * カラム名配列がそろった段階で、イベントが発生します。
482         *
483         * openGion での標準的な処理は、colNo==0 の時に、val の先頭が、#NAME
484         * で始まるレコードを、名前配列として認識します。
485         * #value( String,int,int ) で、この #NAME だけは、継続処理されます。
486         * その上で、#NAME レコードが終了した時点で、カラム名配列が完成するので
487         * そこで初めて、このメソッドが呼ばれます。(EXCEL関係の場合)
488         *
489         * 外部から設定する、#setNames( String , boolean ) 時も同様に呼ばれます。
490         *
491         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
492         *
493         * @param       names   カラム名配列
494         * @see         #value( String,int,int )
495         * @see         #setNames( String , boolean )
496         */
497        public void columnNames( final String[] names ) {
498                if( useDebug ) { System.out.println( "columnNames=[" + Arrays.toString(names) + "]" ); }
499        }
500
501        /**
502         * #NAME のオリジナルカラム名配列がそろった段階で、イベントが発生します。
503         *
504         * #columnNames( String[] ) は、setNames指定時も、#NAME 指定時もイベントが発生します。
505         * このメソッドは、setNames の設定に関係なく、ファイルに書かれていた #NAME で始まるレコードを、
506         * 名前配列として識別して呼出します。
507         *
508         * #NAME が存在しない場合は、呼び出されません。
509         *
510         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのオリジナルを取得できるようにします。
511         *
512         * @param       names   #NAME のオリジナルカラム名配列
513         * @see         #columnNames( String[] )
514         */
515        public void originalNames( final String[] names ) {
516                if( useDebug ) { System.out.println( "originalNames=[" + Arrays.toString(names) + "]" ); }
517        }
518
519        /**
520         * row にあるセルのオブジェクト値がそろった段階で、イベントが発生します。
521         *
522         * 初期実装は、何もありません。
523         *
524         * @og.rev 6.0.3.0 (2014/11/13) 新規作成
525         *
526         * @param       vals    文字列値の1行分の配列
527         * @param       rowNo   行番号(0~)
528         */
529        public void values( final String[] vals,final int rowNo ) {
530                if( useDebug ) { System.out.println( "values[" + rowNo + "]=[" + Arrays.toString(vals) + "]" ); }
531        }
532
533        /**
534         * 外部からCSV形式のカラム名文字列を設定します。
535         *
536         * ※ イベント処理実行前の初期化処理です。
537         *
538         * カラム名配列を、#NAME で始まるレコードではなく、外部から指定します。
539         * ここで設定した場合、#columnNames( String[] )イベントも発生します。
540         * null か、長さゼロのカラム名は、設定されません。
541         *
542         * @og.rev 6.1.0.0 (2014/12/26) カラム名配列設定の対応
543         * @og.rev 7.3.1.3 (2021/03/09) #NAMEのオリジナルを取得できるようにします。
544         *
545         * @param       clms            CSV形式のカラム名文字列
546         * @param       useNumber       行番号情報 [true:使用している/false:していない]
547         * @see         #columnNames( String[] )
548         */
549        public final void setNames( final String clms , final boolean useNumber ) {
550                if( clms != null && clms.length() > 0 ) {
551                        if( useDebug ) { System.out.println( "setNames=[" + clms + "]" ); }
552
553                        colList = new ArrayList<>() ;                                                                           // 初期化
554                        nmsList = new ArrayList<>() ;                                                                           // 初期化
555
556                        final String[] nms = StringUtil.csv2Array( clms );
557                        final int adrs = useNumber ? 1 : 0 ;                                                            // useNumber =true の場合は、1件目(No)は読み飛ばす。
558                        for( int i=0; i<nms.length; i++ ) {
559                                // null か、長さゼロのカラム名は、設定されません。
560                                final String nm = nms[i];
561                                if( nm != null && nm.length() > 0 ) {
562                                        // 2.0.0 (2024/01/12) PMD 7.0.0 UnnecessaryBoxing
563//                                      colList.add( Integer.valueOf( i+adrs ) );
564                                        colList.add( i+adrs );
565                                        nmsList.add( nm );
566                                }
567                        }
568                        isNowName = true;                                                                                                       // 名前設定中
569                        useVals   = false;                                                                                                      // データ未設定
570                        endRow();                                                                                                                       // 行末処理実行。名前設定処理が走ります。
571                }
572        }
573
574        /**
575         * カラム名配列が、設定されたかどうか、返します。
576         *
577         * カラム名配列は、#NAME で始まるレコードか、#setNames( String,boolean )メソッドを
578         * 使用して、外部から指定します。
579         * カラム名配列が未設定の場合は、データもセットできないので、処理の最後の判定に使います。
580         *
581         * @og.rev 6.1.0.0 (2014/12/26) カラム名配列設定の対応
582         *
583         * @return      カラム名配列が、設定されたかどうか(true:設定済み/false:未設定)
584         * @see         #setNames( String,boolean )
585         */
586        public boolean isNameSet() {
587                // clmSize > 0 は、#NAME が設定済みという意味
588                return clmSize > 0;
589        }
590
591        /**
592         * 以降のデータを読み飛ばすかどうかを指定します(初期値:false)。
593         *
594         * データを読み込む途中で、それ以降のデータを読み込む必要がなくなった場合に、
595         * true に設定すると、以降のデータを今のシート/ファイルが終了するまで、スキップします。
596         * 例えば、読み込むべき必須カラムで判定する、nullBreakClm 機能を実現できます。
597         * 初期値は、false:読み飛ばさない です。
598         *
599         * @og.rev 6.1.0.0 (2014/12/26) シートブレイク処理追加
600         *
601         * @param       flag    以降のデータを読み飛ばすかどうか [true:読み飛ばす/false:読み飛ばさない]
602         * @see         #isSkip( int )
603         */
604        public void setReadBreak( final boolean flag ) {
605                isReadBreak = flag ;
606        }
607
608        /**
609         * 先頭データの読み飛ばし件数を設定します。
610         *
611         * ※ イベント処理実行前の初期化処理です。
612         *
613         * データの読み始めの行を指定します。
614         * シート/ファイルの先頭行が、0行としてカウントしますので、設定値は、読み飛ばす
615         * 件数になります。(1と指定すると、1件読み飛ばし、2件目から読み込みます。)
616         * 読み飛ばしは、コメント行などは、無視しますので、実際の行数分読み飛ばします。
617         * #NAME属性や、columns 属性は、読み飛ばし中でも処理対象行になります。
618         *
619         * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
620         *
621         * @param       count   読み始めの初期値(0なら、読み飛ばしなし)
622         */
623        public void setSkipRowCount( final int count ) {
624                skipRowCnt = count;
625        }
626
627        /**
628         * ここに指定されたカラム列に NULL/ゼロ文字列 が現れた時点でSheetの読み取りを中止します。
629         *
630         * これは、指定のカラムは必須という事を条件に、そのレコードだけを読み取る処理を行います。
631         * 複数Sheetの場合は、次のSheetを読みます。
632         * Sheetが存在しない場合(通常のテキスト等)では、読み取り処理の終了になります。
633         *
634         * @og.rev 6.2.0.0 (2015/02/27) 新規追加
635         *
636         * @param       clm     カラム列
637         */
638        public void setNullBreakClm( final String clm ) {
639                nullBreakClm = clm;
640        }
641
642        /**
643         * ここに指定されたカラム列に NULL が現れたレコードは読み飛ばします。
644         *
645         * 例えば、更新対象カラムで、null の場合は、何もしない、などのケースで使用できます。
646         * 複数カラムの場合は、AND条件やOR条件などが、考えられるため、
647         * カラムを一つにまとめて、指定してください。
648         *
649         * @og.rev 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
650         *
651         * @param       clm     カラム列
652         */
653        public void setNullSkipClm( final String clm ) {
654                nullSkipClm = clm;
655        }
656
657        /**
658         * 固定値となるカラム名(CSV形式)と、固定値となるアドレス(行-列,行-列...) or(A1,B3...)を設定します。
659         *
660         * ※ イベント処理実行前の初期化処理です。
661         *
662         * アドレスは、EXCEL上の行-列か、EXCEL列のA1,B3 などの形式を、CSV形式で指定します。
663         * 行列は、EXCELオブジェクトに準拠するため、0から始まる整数です。
664         * 0-0 ⇒ A1 , 1-0 ⇒ A2 , 0-1 ⇒ B1 になります。
665         * これにより、シートの一か所に書かれている情報を、DBTableModel のカラムに固定値として
666         * 設定することができます。
667         * 例として、DB定義書で、テーブル名をシートの全レコードに設定したい場合などに使います。
668         *
669         * 5.7.6.3 (2014/05/23) より、
670         *   ①EXCEL表記に準拠した、A1,A2,B1 の記述も処理できるように対応します。
671         *     なお、A1,A2,B1 の記述は、必ず、英字1文字+数字 にしてください。(A~Zまで)
672         *     EXCEL2007形式で列数が拡張されていますが、列数は制限しています。
673         *   ②処理中のEXCELシート名をカラムに割り当てるために、"SHEET" という記号に対応します。
674         * 6.2.0.0 (2015/02/27) より、
675         *   ③EXCEL以外では、"FILE","NAME","SUFIX" が使えます。(EXCEL時にも使えます。)
676         *     NAME は、ファイル名から拡張子を取り除いた文字列になります。(AAA/BBB/CCC.xls → CCC)
677         * 例えば、sheetConstKeys="CLM,LANG,NAME" とし、sheetConstAdrs="0-0,A2,SHEET" とすると、
678         * NAMEカラムには、シート名を読み込むことができます。
679         * これは、内部処理の簡素化のためです。
680         *
681         * ちなみに、EXCELのセルに、シート名を表示させる場合の関数は、下記の様になります。
682         * =RIGHT(CELL("filename",$A$1),LEN(CELL("filename",$A$1))-FIND("]",CELL("filename",$A$1)))
683         *
684         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
685         * @og.rev 5.7.6.3 (2014/05/23) EXCEL表記(A2,B1等)の対応と、特殊記号(SHEET)の対応
686         * @og.rev 6.1.0.0 (2014/12/26) カラム名配列設定の対応
687         *
688         * @param       constKeys       固定値となるカラム名(CSV形式)
689         * @param       constAdrs       固定値となるアドレス(行-列,行-列...) or(A1,B3...)
690         */
691        public void setConstData( final String constKeys,final String constAdrs ) {
692                if( constKeys != null && !constKeys.isEmpty() && constAdrs != null && !constAdrs.isEmpty() ) {
693                        cnstData = new ConstData( constKeys,constAdrs );
694                        // setNames( String , boolean ) と、このメソッドの呼び出し順に影響がないようにするため。
695                        if( names != null ) { cnstData.setColumns( names ); }
696                }
697        }
698
699        /**
700         * デバッグ情報を出力するかどうか[true:する/false:しない]を指定します。
701         *
702         * EXCELなどを読み取る場合、シートマージで読み取ると、エラー時の行番号が、連番になるため、
703         * どのシートなのか、判らなくなります。
704         * そこで、どうしてもわからなくなった場合に備えて、デバッグ情報を出力できるようにします。
705         * 通常は使用しませんので、設定を無視します。
706         * 初期値は、false:デバッグ情報を出力しない です。
707         *
708         * @og.rev 6.2.0.0 (2015/02/27) デバッグ情報の出力するかどうか。新規追加
709         *
710         * @param       useDebug        デバッグ出力するか [true:する/false:しない]
711         */
712        public void setDebug( final boolean useDebug ) {
713                this.useDebug = useDebug;
714        }
715
716        /**
717         * デバッグ情報を出力するかどうか[true:する/false:しない]を取得します。
718         *
719         * EXCELなどを読み取る場合、シートマージで読み取ると、エラー時の行番号が、連番になるため、
720         * どのシートなのか、判らなくなります。
721         * そこで、どうしてもわからなくなった場合に備えて、デバッグ情報を出力できるようにします。
722         *
723         * @og.rev 6.2.0.0 (2015/02/27) デバッグ情報の出力するかどうか。新規追加
724         *
725         * @return      デバッグ出力 [true:する/false:しない]
726         */
727        protected boolean isDebug() {
728                return useDebug ;
729        }
730
731        /**
732         * EXCELファイルの所定の位置から、固定値を取り出す処理を管理します。
733         *
734         * この固定値の取出しは、内部処理に、非常に依存しているため、今は、
735         * TableModelHelper クラスに含めていますが、将来的には、分ける予定です。
736         *
737         * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
738         * @og.rev 6.2.0.0 (2015/02/27) 特殊記号(FILE,NAME,SUFIX)追加
739         *
740         * @version     6.0
741         * @author      Kazuhiko Hasegawa
742         * @since       JDK7.0,
743         */
744        private static final class ConstData {
745                /** 内部情報のクリア方法の指定 {@value} */
746                public static final int END_FILE  = 1 ;
747                /** 内部情報のクリア方法の指定 {@value} */
748                public static final int END_SHEET = 2 ;
749
750                // 6.2.0.0 (2015/02/27) 特殊記号処理 追加 (SHEET,FILE,NAME,SUFIX)
751                private static final String KEYS = ",SHEET,FILE,NAME,SUFIX,";
752
753                // ①cnstMap は、cnstKey をキーに、拾ってきた値を持っています。(Sheet毎のトランザクション)
754                private final Map<String,String> cnstMap = new HashMap<>();                             // 6.1.0.0 (2014/12/26) Mapで管理
755                // ②rowcolMap は、rowcol をキーに、アドレスを持っています。
756                private final Map<String,Integer> rowcolMap = new HashMap<>();                  // 6.1.0.0 (2014/12/26) Mapで管理
757                // ③valsMap は、アドレス をキーに、拾ってきた値を持っています。(Sheet毎のトランザクション)
758                private final Map<Integer,String> valsMap = new HashMap<>();                    // 6.1.0.0 (2014/12/26) Mapで管理
759
760                private final int maxRow  ;             // 6.4.9.1 (2016/08/05) final化。最大値持っておき、判定処理を早める。
761
762                // ※ rowcolMap を使用する為、必ず #setColumns( String... ) の実行後に行います。
763                private boolean isNameSet ;
764                private File    tmpFile   ;
765                private String  tmpShtNm  ;
766
767                /**
768                 * 固定値となるカラム名(CSV形式)と、固定値となるアドレス(行-列,行-列...) or(A1,B3...)を設定します。
769                 *
770                 * アドレスは、EXCEL上の行-列か、EXCEL列のA1,B3 などの形式を、CSV形式で指定します。
771                 * 行列は、EXCELオブジェクトに準拠するため、0から始まる整数です。
772                 * 0-0 ⇒ A1 , 1-0 ⇒ A2 , 0-1 ⇒ B1 になります。
773                 * これにより、シートの一か所に書かれている情報を、DBTableModel のカラムに固定値として
774                 * 設定することができます。
775                 * 例として、DB定義書で、テーブル名をシートの全レコードに設定したい場合などに使います。
776                 *
777                 * 5.7.6.3 (2014/05/23) より、
778                 *   ①EXCEL表記に準拠した、A1,A2,B1 の記述も処理できるように対応します。
779                 *     なお、A1,A2,B1 の記述は、必ず、英字1文字+数字 にしてください。(A~Zまで)
780                 *     EXCEL2007形式で列数が拡張されていますが、列数は制限しています。
781                 *   ②処理中のEXCELシート名をカラムに割り当てるために、"SHEET" という記号に対応します。
782                 * 6.2.0.0 (2015/02/27) より、
783                 *   ③EXCEL以外では、"FILE","NAME","SUFIX" が使えます。
784                 *     NAME は、ファイル名から拡張子を取り除いた文字列になります。(AAA/BBB/CCC.xls → CCC)
785                 * 例えば、sheetConstKeys="CLM,LANG,SHT" とし、sheetConstAdrs="0-0,A2,SHEET" とすると、
786                 * SHTカラムには、シート名を読み込むことができます。
787                 * これは、内部処理の簡素化のためです。
788                 *
789                 * ちなみに、EXCELのセルに、シート名を表示させる場合の関数は、下記の様になります。
790                 * =RIGHT(CELL("filename",$A$1),LEN(CELL("filename",$A$1))-FIND("]",CELL("filename",$A$1)))
791                 *
792                 * @og.rev 5.5.8.2 (2012/11/09) 新規追加
793                 * @og.rev 5.7.6.3 (2014/05/23) EXCEL表記(A2,B1等)の対応と、特殊記号(SHEET)の対応
794                 * @og.rev 6.1.0.0 (2014/12/26) カラム名配列設定の対応
795                 * @og.rev 6.2.0.0 (2015/02/27) 特殊記号(FILE,NAME,SUFIX)の追加対応
796                 * @og.rev 6.4.9.1 (2016/08/05) maxRowをfinal化します。
797                 *
798                 * @param       constKeys       固定値となるカラム名(CSV形式)
799                 * @param       constAdrs       固定値となるアドレス(行-列,行-列...) or(A1,B3...)
800                 */
801                /* default */ ConstData( final String constKeys,final String constAdrs ) {
802                        final String[] cnstKeys = constKeys.split( "," );
803                        // 8.5.5.1 (2024/02/29) PMD 7.0.0 LocalVariableNamingConventions
804//                      final String[] row_col = constAdrs.split( "," );
805                        final String[] rowCols = constAdrs.split( "," );
806
807//                      if( cnstKeys.length != row_col.length ) {
808                        if( cnstKeys.length != rowCols.length ) {
809                                final String errMsg = "キーに対するアドレスの個数が不一致です。Keys=[" + constKeys + "]"
810                                                        + " , Adrs=[" + constAdrs + "]" ;
811                                throw new OgRuntimeException( errMsg );
812                        }
813
814                        int tmpRow = -1;                                                                                                        // 6.4.9.1 (2016/08/05)
815                        // 初期の カラムとアドレス(キーワード)の関連付け
816                        for( int j=0; j<cnstKeys.length; j++ ) {
817                                final String cnstKey = cnstKeys[j].trim();                                              // 前後の不要なスペースを削除
818                                if( !cnstKey.isEmpty() ) {
819//                                      String rowcol = row_col[j].trim();                                                      // 前後の不要なスペースを削除
820                                        String rowcol = rowCols[j].trim();                                                      // 前後の不要なスペースを削除
821                                        if( !rowcol.isEmpty() ) {
822                                                // 5.7.6.3 (2014/05/23) EXCEL表記(A2,B1等)の対応と、特殊記号(SHEET)の対応
823                                                final int sep = rowcol.indexOf( '-' );
824                                                if( sep > 0 ) {
825                                                        final int row = Integer.parseInt( rowcol.substring( 0,sep ) );
826                        //                              int col = Integer.parseInt( rowcol.substring( sep+1 ) );
827                                                        if( tmpRow < row ) { tmpRow = row; }                            // 6.4.9.1 (2016/08/05)
828                        //                              rowcol = String.valueOf( (char)('A' + col) ) + String.valueOf( row + 1 ) ;      // row-col 形式なので、不要
829                                                }
830                                                // 6.2.0.0 (2015/02/27) 特殊記号(SHEET,FILE,NAME,SUFIX)の追加対応
831                                                else if( !KEYS.contains( ',' + rowcol + ',' ) ) {
832                                                        final int row = Integer.parseInt( rowcol.substring( 1 ) ) -1;   // C6 の場合、rowは、6-1=5
833                                                        final int col = rowcol.charAt(0) - 'A' ;                                                // C6 の場合、colは、'C'-'A'=2
834                                                        if( tmpRow < row ) { tmpRow = row; }                            // 6.4.9.1 (2016/08/05)
835                                                        rowcol = row + "-" + col ;
836                                                }
837                                                cnstMap.put( cnstKey , rowcol );                                                // 6.1.0.0 (2014/12/26) cnstMap に行列情報を設定する
838                                        }
839                                }
840                        }
841                        maxRow = tmpRow;
842                }
843
844                /**
845                 * カラム名配列を元に、固定値カラムのアドレスを求めます。
846                 * カラム名配列は、順番に、指定する必要があります。
847                 *
848                 * @og.rev 6.1.0.0 (2014/12/26) カラム名配列設定の対応
849                 *
850                 * @param       names   カラム列配列(可変長引数)
851                 */
852                /* default */ void setColumns( final String... names ) {
853                        // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
854                        if( names != null && names.length > 0 ) {
855                                // 5.5.8.2 (2012/11/09) 固定値取得用の cnstIndx の設定を行う。
856                                for( int i=0; i<names.length; i++ ) {
857                                        final String rowcol = cnstMap.get( names[i] );          // cnstKey があれば、rowcol が取得できるはず
858                                        if( rowcol != null ) {
859                                                // 2.0.0 (2024/01/12) PMD 7.0.0 UnnecessaryBoxing
860//                                              rowcolMap.put( rowcol , Integer.valueOf( i ) );
861                                                rowcolMap.put( rowcol ,i );
862                                        }
863                                }
864                                isNameSet = true;                       // 名前設定がされないと、FILEやSHEET キーワードが使えない。
865
866                                if( tmpFile  != null ) { putConstFile(  tmpFile  ); }
867                                if( tmpShtNm != null ) { putConstSheet( tmpShtNm ); }
868                        }
869                }
870
871                /**
872                 * 読み取り時に、rowNo,colNo にあるセルの値を、固定値となるカラム名に関連付けます。
873                 *
874                 * イベントモデルでは、固定値の指定アドレス(rowNo,colNo)をピンポイントで取得することが
875                 * できないため、イベント発生毎に、チェックする必要があります。
876                 * そのため、固定値を使用すると、処理速度が低下します。
877                 *
878                 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
879                 *
880                 * @param       val             文字列値(null またはゼロ文字列は、不可)
881                 * @param       rowNo   行番号(0~)
882                 * @param       colNo   列番号(0~)
883                 */
884                /* default */ void putConstValue( final String val,final int rowNo,final int colNo ) {
885                        if( rowNo <= maxRow ) {
886                                final String rowcol = rowNo + "-" + colNo ;
887                                final Integer adrs = rowcolMap.get( rowcol );
888                                if( adrs != null ) {
889                                        valsMap.put( adrs,val );
890                                }
891                        }
892                }
893
894                /**
895                 * ファイル系特殊記号(FILE,NAME,SUFIX)を指定します。
896                 *
897                 * ../AAA/BBB/CCC.XLS というファイルオブジェクトに対して、
898                 *   FILE    : CCC.XLS ファイル名
899                 *   NAME    : CCC     拡張子なしのファイル名
900                 *   SUFIX   : xls     ピリオド無しの拡張子(小文字に統一)
901                 *
902                 * これは、新しいファイルの読み取り開始時に、設定します。
903                 *
904                 * ※ rowcolMap を使用する為、必ず #setColumns( String... ) の実行後に行います。
905                 *
906                 * @og.rev 6.2.0.0 (2015/02/27) 新規作成
907                 *
908                 * @param       filNm   指定ファイル
909                 */
910                /* default */ void putConstFile( final File filNm ) {
911                        if( filNm != null ) {
912                                tmpFile = filNm;                // 名前設定がされるまで、一時保管する。(順番があるので呼ばれればセットしておく)
913                                if( isNameSet ) {               // 名前設定がされないと、FILEやSHEET キーワードが使えない。
914                                        final FileInfo info = new FileInfo( filNm );
915
916                                        for( final String key : FileInfo.KEY_LIST ) {
917                                                final Integer adrs = rowcolMap.get( key );
918                                                if( adrs != null ) {
919                                                        final String val = info.getValue( key );
920                                                        if( val != null ) {
921                                                                valsMap.put( adrs,val );
922                                                        }
923                                                }
924                                        }
925                                }
926                        }
927                }
928
929                /**
930                 * シート名を外部から指定します。
931                 * アドレス指定の特殊系として、"SHEET" 文字列を指定できます。
932                 * これは、新しいシートの読み取り開始時に、設定します。
933                 *
934                 * ※ rowcolMap を使用する為、必ず #setColumns( String... ) の実行後に行います。
935                 *
936                 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
937                 *
938                 * @param       shtNm   シート名
939                 */
940                /* default */ void putConstSheet( final String shtNm ) {
941                        if( shtNm != null ) {
942                                tmpShtNm = shtNm;               // 名前設定がされるまで、一時保管する。
943                                if( isNameSet ) {               // 名前設定がされないと、FILEやSHEET キーワードが使えない。
944                                        final Integer adrs = rowcolMap.get( "SHEET" );
945                                        if( adrs != null ) {
946                                                valsMap.put( adrs,shtNm );
947                                        }
948                                }
949                        }
950                }
951
952                /**
953                 * 内部の valsMap を初期化します。
954                 * 固定値の読み取りは、シートごとに行います。
955                 * 新しいシートにデータが設定されていない場合、前のシートの値が残ります。
956                 * ここでは、シート呼出しごとに、毎回クリアします。
957                 * 引数に応じて、クリアする範囲を限定します。
958                 * END_FILE 時は、すべてクリア。END_SHEET 時は、ファイル情報は残します。
959                 *
960                 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
961                 *
962                 * @param       type    内部情報のクリア方法の指定(END_FILE or END_SHEET)
963                 */
964                /* default */ void clearValsMap( final int type ) {
965                        valsMap.clear();
966                        if( type == END_SHEET ) { putConstFile( tmpFile ); }    // 全削除後にファイル情報を再設定
967                }
968
969                /**
970                 * 値配列のデータに、固定値を設定します。
971                 * 引数の文字列配列に、固定値を設定しますので、配列オブジェクト自体を更新します。
972                 *
973                 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善
974                 * @og.rev 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。
975                 *
976                 * @param       vals    文字列値の1行分の配列
977                 * @return      固定値を設定された1行分の文字列配列
978                 */
979                /* default */ String[] getConstVals( final String[] vals ) {
980                        if( vals != null && vals.length > 0 ) {
981                                // 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。
982                                valsMap.forEach( (k,v) -> {
983                                                        if( k < vals.length ) { vals[k] = v; }
984                                } );
985                        }
986                        return vals ;
987                }
988        }
989}