    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.process;
    017
    018import org.opengion.fukurou.system.OgRuntimeException ;                         // 6.4.2.0 (2016/01/29)
    019import org.opengion.fukurou.system.OgCharacterException ;                       // 6.5.0.1 (2016/10/21)
    020import org.opengion.fukurou.system.DateSet;                                                     // 6.4.2.0 (2016/01/29)
    021import org.opengion.fukurou.system.Closer;
    022import org.opengion.fukurou.util.FileUtil;
    023import org.opengion.fukurou.util.CommentLineParser;
    024import org.opengion.fukurou.util.FileInfo;                                                      // 6.4.0.2 (2015/12/11)
    025import org.opengion.fukurou.security.HybsCryptography ;                         // 5.7.2.1 (2014/01/17)
    026import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.3.1.0 (2015/06/28)
    027
    028import java.io.File;
    029import java.io.BufferedReader;
    030import java.io.PrintWriter;
    031import java.io.IOException;
    032import java.nio.charset.CharacterCodingException;                                       // 6.3.1.0 (2015/06/28)
    033
    034/**
    035 * FileLineModel は、LineModel を継承した ﾌｧｲﾙﾘｽﾄ専用の
    036 * LineModel の実装ｸﾗｽです。
    037 *
    038 * FileLineModel ｵﾌﾞｼﾞｪｸﾄには、ﾌｧｲﾙ属性(Level,File,Length,Modify,LineCnt,Biko,MD5)
    039 * が設定されます。
    040 * ｵﾌﾟｼｮﾝで、FILEPATH,ADDRESS,FILENAME 属性を文字列で準備できます。(6.3.1.0 (2015/06/28))
    041 * ADDRESS は、指定ﾌｧｲﾙの親ﾌｫﾙﾀﾞ。FILENAME はﾌｧｲﾙ名。FILEPATH は、ﾌｧｲﾙ名を含む
    042 * 完全なﾌｧｲﾙﾊﾟｽになります。
    043 * ※ 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    044 *    この、新しい属性に、値をｾｯﾄする場合は、useFilePath="true" をｾｯﾄしてください。
    045 * ※ 6.3.1.1 (2015/07/10) Modify のﾌｫｰﾏｯﾄ(modifyForm)を、指定可能にします。
    046 *    これは、Date型のまま、扱いたい所だが、文字列化しています。
    047 *    初期値は、"yyyy/MM/dd HH:mm:ss" です。
    048 *
    049 * LineCnt と、MD5 は、それぞれ、計算するかどうかのﾌﾗｸﾞを設定する必要があります。
    050 *
    051 * ※ useLineCnt=false の場合のLength(文字数)は、File#length() ﾒｿｯﾄﾞで求めます。
    052 *    一方、useLineCnt=true にすると、行単位に、String#length() を加算するため、
    053 *    先のLength(文字数)値とは異なりますのでご注意ください。
    054 *
    055 * omitCmnt=true にすると、ｺﾒﾝﾄ部分を削除した行数と文字数を求めます。
    056 * これは、/&#042; から &#042;/ の間、&#47;&#47; から改行までです。
    057 * ただし、&#034;(二重引用符)で囲まれた文字列は、ｺﾒﾝﾄとみなしません。
    058 *
    059 * 8.1.0.4 (2022/01/28)
    060 *  さらに、各行の空行はｶｳﾝﾄに含めないことにします。
    061 *
    062 * ﾃﾞｰﾀの１行分を FileLineModel に割り当てます。
    063 * ｶﾗﾑ番号は、0 から始まります。ｶﾗﾑ名よりｶﾗﾑ番号を求める場合に、
    064 * 存在しない場合は、-1 を返します。
    065 * ｶﾗﾑ番号が -1 の場合は、処理を行いません。
    066 *
    067 * 注意：このｸﾗｽは、同期処理されていません。
    068 *
    069 * @version  4.0
    070 * @author   Kazuhiko Hasegawa
    071 * @since    JDK5.0,
    072 */
    073public class FileLineModel extends LineModel {
    074        // 5.7.2.1 (2014/01/17) MD5 項目追加
    075        // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    076        private static final String[] KEYS = { "Level","File","Length","Modify","LineCnt","Biko","MD5","FILEPATH","ADDRESS","FILENAME" };
    077
    078        private static final int LEVEL          = 0;
    079        private static final int FILE           = 1;
    080        private static final int LENGTH         = 2;
    081        private static final int MODIFY         = 3;
    082        private static final int LINECNT        = 4;
    083        private static final int BIKO           = 5;
    084        private static final int MD5            = 6;            // 5.7.2.1 (2014/01/17)
    085        private static final int FILEPATH       = 7;            // 6.3.1.0 (2015/06/28)
    086        private static final int ADDRESS        = 8;            // 6.3.1.0 (2015/06/28)
    087        private static final int FILENAME       = 9;            // 6.3.1.0 (2015/06/28)
    088
    089        private final boolean useLineCnt ;
    090        private final boolean useMD5 ;                          // 5.7.2.1 (2014/01/17) MD5 項目追加
    091        private final boolean omitCmnt ;                        // 5.7.4.0 (2014/03/07) ｺﾒﾝﾄ除外の可否(true:除外する)
    092        private final boolean useFilePath ;                     // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性を使う場合は、true
    093        private String encode = "JISAutoDetect";        // 5.7.4.0 (2014/03/07) ｺﾒﾝﾄ削除時の文字数計算で利用するﾌｧｲﾙのｴﾝｺｰﾄﾞ
    094        private String modifyForm = "yyyy/MM/dd HH:mm:ss" ;     // 6.3.1.1 (2015/07/10)
    095
    096        /**
    097         * ｺﾝｽﾄﾗｸﾀｰです。
    098         * useLineCnt=false , useMD5=false , omitCmnt=false で初期化されます。
    099         *
    100         * @og.rev 5.7.2.1 (2014/01/17) MD5対応
    101         * @og.rev 5.7.4.0 (2014/03/07) ｺﾒﾝﾄ除外の可否(true:除外する)対応
    102         * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    103         *
    104         */
    105        public FileLineModel() {
    106                this( false,false,false,false );                // 6.3.1.0 (2015/06/28)
    107        }
    108
    109        /**
    110         * ﾗｲﾝｶｳﾝﾄの有無を指定した、ｺﾝｽﾄﾗｸﾀｰです。
    111         * useMD5=false , omitCmnt=false で初期化されます。
    112         *
    113         * @og.rev 4.2.2.0 (2008/05/10) 行数ｶｳﾝﾄの使用有無
    114         * @og.rev 5.7.2.1 (2014/01/17) MD5対応
    115         * @og.rev 5.7.4.0 (2014/03/07) ｺﾒﾝﾄ除外の可否(true:除外する)対応
    116         * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    117         *
    118         * @param       isLineCnt       行数ｶｳﾝﾄの使用有無
    119         */
    120        public FileLineModel( final boolean isLineCnt ) {
    121                this( isLineCnt,false,false,false );            // 6.3.1.0 (2015/06/28)
    122        }
    123
    124        /**
    125         * ﾗｲﾝｶｳﾝﾄの有無と、MD5計算の有無を指定した、ｺﾝｽﾄﾗｸﾀｰです。
    126         * omitCmnt=false で初期化されます。
    127         *
    128         * @og.rev 5.7.2.1 (2014/01/17) 新規追加(MD5対応)
    129         * @og.rev 5.7.4.0 (2014/03/07) ｺﾒﾝﾄ除外の可否(true:除外する)対応
    130         * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加。
    131         *
    132         * @param       isLineCnt       行数ｶｳﾝﾄの使用有無
    133         * @param       isMD5           ﾌｧｲﾙのMD5の使用有無
    134         */
    135        public FileLineModel( final boolean isLineCnt,final boolean isMD5 ) {
    136                this( isLineCnt,isMD5,false,false );            // 6.3.1.0 (2015/06/28)
    137        }
    138
    139        /**
    140         * ﾗｲﾝｶｳﾝﾄの有無と、MD5計算の有無と、ｺﾒﾝﾄ除外の可否を指定した、ｺﾝｽﾄﾗｸﾀｰです。
    141         *
    142         * @og.rev 5.7.4.0 (2014/03/07) ｺﾒﾝﾄ除外の可否(true:除外する)
    143         * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    144         *
    145         * @param       isLineCnt       行数ｶｳﾝﾄの使用有無
    146         * @param       isMD5           ﾌｧｲﾙのMD5の使用有無
    147         * @param       isOmit          ｺﾒﾝﾄ除外の可否(true:除外する)
    148         */
    149        public FileLineModel( final boolean isLineCnt,final boolean isMD5,final boolean isOmit ) {
    150                this( isLineCnt,isMD5,isOmit,false );   // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    151        }
    152
    153        /**
    154         * ﾗｲﾝｶｳﾝﾄの有無と、MD5計算の有無と、ｺﾒﾝﾄ除外の可否と、追加属性可否を指定した、ｺﾝｽﾄﾗｸﾀｰです。
    155         *
    156         * @og.rev 5.7.4.0 (2014/03/07) ｺﾒﾝﾄ除外の可否(true:除外する)
    157         * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    158         * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
    159         *
    160         * @param       isLineCnt       行数ｶｳﾝﾄの使用有無
    161         * @param       isMD5           ﾌｧｲﾙのMD5の使用有無
    162         * @param       isOmit          ｺﾒﾝﾄ除外の可否(true:除外する)
    163         * @param       isPath          FILEPATH,ADDRESS,FILENAME 属性の可否(true:使用する)
    164         */
    165        public FileLineModel( final boolean isLineCnt,final boolean isMD5,final boolean isOmit,final boolean isPath ) {
    166                super();
    167                // 4.3.4.4 (2009/01/01)
    168                useLineCnt      = isLineCnt;
    169                useMD5          = isMD5;                                // 5.7.2.1 (2014/01/17)
    170                omitCmnt        = isOmit;                               // 5.7.4.0 (2014/03/07)
    171                useFilePath     = isPath;                               // 5.7.4.0 (2014/03/07)
    172                init( KEYS );
    173        }
    174
    175        /**
    176         * LineModel を元に、FileLineModel を構築します。
    177         * これは、一旦ﾌｧｲﾙ等にｾｰﾌﾞされた FileLineModel 形式を
    178         * 元に戻す簡易ｺﾝｽﾄﾗｸﾀです。
    179         *
    180         * @og.rev 4.2.3.0 (2008/05/26) 新規追加
    181         * @og.rev 5.7.2.1 (2014/01/17) MD5の設定処理追加
    182         * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    183         * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
    184         *
    185         * @param       model   元のLineModel
    186         */
    187        public FileLineModel( final LineModel model ) {
    188                super();
    189                // 4.3.4.4 (2009/01/01)
    190                init( model.getNames() );
    191
    192                final Object[] obj = model.getValues();
    193
    194                setValue( LEVEL   ,Integer.valueOf( (String)obj[LEVEL] ) );
    195                setValue( FILE    ,new File((String)obj[FILE]) );
    196                setValue( LENGTH  ,Long.valueOf( (String)obj[LENGTH] ) );
    197                setValue( MODIFY  ,(String)obj[MODIFY] );
    198
    199                final String cnt = (String)obj[LINECNT] ;
    200                useLineCnt = cnt != null && cnt.length() > 0 && ! "null".equalsIgnoreCase( cnt ) ;
    201                if( useLineCnt ) { setValue( LINECNT ,cnt ); }
    202
    203                setValue( BIKO  ,(String)obj[BIKO] );
    204
    205                // 5.7.2.1 (2014/01/17)
    206                final String md5Data = (String)obj[MD5] ;
    207                useMD5 = md5Data != null && md5Data.length() > 0 && ! "null".equalsIgnoreCase( md5Data ) ;
    208                if( useMD5 ) { setValue( MD5 ,md5Data ); }
    209
    210                omitCmnt   = false;                     // 5.7.4.0 (2014/03/07) 既存の LineModel から取得できないので、強制設定します。
    211
    212                // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    213                // 念のため、配列数をﾁｪｯｸしながら処理します。
    214                if( obj.length > FILEPATH ) {
    215                        final String path = (String)obj[FILEPATH] ;
    216                        useFilePath = path != null && path.length() > 0 && ! "null".equalsIgnoreCase( path ) ;
    217                        if( useFilePath ) {
    218                                setValue( FILEPATH ,path );
    219                                if( obj.length > ADDRESS  ) { setValue( ADDRESS  ,(String)obj[ADDRESS]  ); }
    220                                if( obj.length > FILENAME ) { setValue( FILENAME ,(String)obj[FILENAME] ); }
    221                        }
    222                }
    223                else {
    224                        useFilePath = false;
    225                }
    226        }
    227
    228        /**
    229         * File属性値をｾｯﾄします。
    230         * LEVEL,FILE,LENGTH,MODIFY,LINECNT,MD5 の各属性を設定します。
    231         *
    232         * @og.rev 4.2.2.0 (2008/05/10) 行数ｶｳﾝﾄの使用有無
    233         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
    234         * @og.rev 5.7.2.1 (2014/01/17) MD5計算処理の追加
    235         * @og.rev 5.7.4.0 (2014/03/07) ｺﾒﾝﾄ除外の可否(true:除外する)対応
    236         * @og.rev 5.7.7.1 (2014/06/13) omitCmnt=true(ｺﾒﾝﾄ除外する) and useMD5=true(MD5計算する) 場合の処理
    237         * @og.rev 6.2.1.0 (2015/03/13) ﾌｧｲﾙの削除に失敗するため、削除しない。
    238         * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    239         * @og.rev 8.1.2.0 (2022/03/10) getMD5 ﾒｿｯﾄﾞを getHash ﾒｿｯﾄﾞに変更
    240         *
    241         * @param       level   ﾌｧｲﾙのﾃﾞｨﾚｸﾄﾘ階層
    242         * @param       file    ﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄ
    243         */
    244        public void setFileVals( final int level, final File file ) {
    245                setValue( LEVEL  ,Integer.valueOf( level ) );
    246                setValue( FILE   ,file );
    247                setValue( MODIFY ,DateSet.getDate( file.lastModified(),modifyForm ) );                                  // 6.3.1.1 (2015/07/10)
    248
    249                // 5.7.7.1 (2014/06/13) omitCmnt=true(ｺﾒﾝﾄ除外する) and useMD5=true(MD5計算する) 場合の処理
    250                // 別にｺﾒﾝﾄ除去されたﾌｧｲﾙを作成して、それの MD5 を求める。
    251                File ocFile = null;
    252                if( omitCmnt && useMD5 ) {
    253                        try {
    254                                ocFile = File.createTempFile( "temp",".tmp" );
    255                                ocFile.deleteOnExit();                                                          // 一応、このﾒｿｯﾄﾞ内で削除しますが、念のため。
    256                        }
    257                        catch( final IOException ex ) {
    258                                final String errMsg = "コメント除外のMD5計算用 temp ファイルの作成に失敗しました。" + ex.getMessage() ;
    259                                throw new OgRuntimeException( errMsg,ex );
    260                        }
    261                }
    262
    263                if( useLineCnt || omitCmnt ) {
    264                        final long[] cntVals = getLineCnt( file,ocFile );                       // 5.7.7.1 (2014/06/13) 出力ﾌｧｲﾙを渡します。
    265                        setValue( LINECNT ,String.valueOf( cntVals[0] ) );
    266                        setValue( LENGTH  ,Long.valueOf(   cntVals[1] ) );
    267                }
    268                else {
    269                        setValue( LENGTH  ,Long.valueOf( file.length() ) );
    270                }
    271
    272                // 5.7.2.1 (2014/01/17) MD5計算がtrue で、かつ、ﾌｧｲﾙの場合、MD5 計算を行います。
    273                if( useMD5 && file.isFile() ) {
    274                        // 5.7.7.1 (2014/06/13) omitCmnt を考慮したMD5計算
    275                        if( ocFile == null ) {
    276//                              setValue( MD5 ,HybsCryptography.getMD5( file ) );                               // 8.1.2.0 (2022/03/10) Modify
    277                                setValue( MD5 ,HybsCryptography.getHash( "MD5", file ) );
    278                        }
    279                        else {
    280//                              setValue( MD5 ,HybsCryptography.getMD5( ocFile ) );                             // 8.1.2.0 (2022/03/10) Modify
    281                                setValue( MD5 ,HybsCryptography.getHash( "MD5", ocFile ) );
    282                                // 6.0.2.4 (2014/10/17) RV  java.io.File.delete() の例外的戻り値を無視しています。
    283                                // 6.2.1.0 (2015/03/13) ﾌｧｲﾙの削除に失敗するため、削除しない。
    284                        }
    285                }
    286
    287                // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    288                if( useFilePath ) {
    289                        // FILEPATH は、正規のﾊﾟｽ名文字列 を求めるが、ｴﾗｰ時は、絶対ﾊﾟｽ名文字列 にする。
    290                        try {
    291                                setValue( FILEPATH      , file.getCanonicalPath() );    // 正規のﾊﾟｽ名文字列
    292                        }
    293                        catch( final IOException ex ) {
    294                                setValue( FILEPATH      , file.getAbsolutePath() );             // 絶対ﾊﾟｽ名文字列
    295                        }
    296
    297                        // ADDRESS は、親の名前なので、直ﾌｫﾙﾀﾞ名になる。
    298                        final File parent = file.getParentFile();
    299                        if( parent != null ) {
    300                                setValue( ADDRESS       ,parent.getName() );
    301                        }
    302
    303                        setValue( FILENAME      ,file.getName() );
    304                }
    305        }
    306
    307        /**
    308         * ｺﾒﾝﾄ削除時の文字数計算で利用するﾌｧｲﾙのｴﾝｺｰﾄﾞをｾｯﾄします。
    309         * 初期値:JISAutoDetect
    310         *
    311         * @og.rev 5.7.4.0 (2014/03/07) 新規追加
    312         *
    313         * @param       encode  ｺﾒﾝﾄ削除時の文字数計算で利用するﾌｧｲﾙのｴﾝｺｰﾄﾞ
    314         */
    315        public void setEncode( final String encode ) {
    316                this.encode = encode;
    317        }
    318
    319        /**
    320         * File属性値をｾｯﾄします。
    321         *
    322         * @param       file    ﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄ
    323         */
    324        public void setFile( final File file ) {
    325                setValue( FILE,file );
    326        }
    327
    328        /**
    329         * ﾌｧｲﾙを取得します。
    330         *
    331         * @return      ﾌｧｲﾙ
    332         */
    333        public File getFile() {
    334                return (File)getValue( FILE );
    335        }
    336
    337        /**
    338         * 備考情報属性値をｾｯﾄします。
    339         *
    340         * @og.rev 4.2.2.0 (2008/05/10) 行数ｶｳﾝﾄの使用有無
    341         *
    342         * @param       biko    備考情報
    343         */
    344        public void setBiko( final String biko ) {
    345                setValue( BIKO,biko );
    346        }
    347
    348        /**
    349         * ﾚﾍﾞﾙ File属性値を取得します。
    350         *
    351         * @return      ﾌｧｲﾙのﾃﾞｨﾚｸﾄﾘ階層
    352         */
    353        public int getLevel() {
    354                return ((Integer)getValue( LEVEL )).intValue();
    355        }
    356
    357        /**
    358         * ﾌｧｲﾙｻｲｽﾞ File属性値を取得します。
    359         *
    360         * @return      ﾌｧｲﾙｻｲｽﾞ
    361         */
    362        public long getLength() {
    363                return ((Long)getValue( LENGTH )).longValue();
    364        }
    365
    366        /**
    367         * 更新日時(Modify) のﾌｫｰﾏｯﾄを、指定します。
    368         *
    369         * ここで指定しない場合は、"yyyy/MM/dd HH:mm:ss" になります。
    370         * Date型で変換できないようなﾌｫｰﾑを指定した場合は、実行時に
    371         * ｴﾗｰになりますので、ご注意ください。
    372         *
    373         * @og.rev 6.3.1.1 (2015/07/10) Modify のﾌｫｰﾏｯﾄを、指定可能にします。
    374         *
    375         * @param       form 更新日時のﾌｫｰﾏｯﾄ
    376         * @see         java.text.SimpleDateFormat
    377         */
    378        public void setModifyForm( final String form ) {
    379                if( form != null && !form.isEmpty() ) {
    380                        modifyForm = form;
    381                }
    382        }
    383
    384        /**
    385         * 更新日時 File属性値を取得します。
    386         *
    387         * @return      更新日時(yyyy/MM/dd HH:mm:ss)
    388         */
    389        public String getModify() {
    390                return (String)getValue( MODIFY );
    391        }
    392
    393        /**
    394         * MD5 File属性値を取得します。
    395         * ただし、useMD5 が true でないと値は返しません。
    396         *
    397         * @og.rev 5.7.2.1 (2014/01/17) 新規追加(MD5対応)
    398         *
    399         * @return      MD5の値
    400         */
    401        public String getMD5() {
    402                return (String)getValue( MD5 );
    403        }
    404
    405        /**
    406         * 行数と文字数を取得します。
    407         * 行数ｶｳﾝﾄとﾌｧｲﾙの文字数ｶｳﾝﾄ(ﾊﾞｲﾄ数ではありません)を行います。
    408         * ※ useLineCnt=false の場合のLength(文字数)は、File#length() ﾒｿｯﾄﾞで求めます。
    409         *    一方、useLineCnt=true にすると、行単位に、String#length() を加算するため、
    410         *    先のLength(文字数)値とは異なりますのでご注意ください。
    411         *
    412         * 結果は、long型の配列で返します。[0]が行数で、[1]が文字数です。
    413         * omitCmnt 属性を使用した場合は、ｺﾒﾝﾄ部分を削除した行数と文字数を求めます。
    414         * これは、/&#042; から &#042;/ の間、&#47;&#47; から改行までです。
    415         * ただし、&#034;(二重引用符)で囲まれた文字列は、ｺﾒﾝﾄとみなしません。
    416         *
    417         * @og.rev 5.7.4.0 (2014/03/07) 行数ｶｳﾝﾄとﾌｧｲﾙの文字数ｶｳﾝﾄを行う。
    418         * @og.rev 5.7.7.1 (2014/06/13) omitCmnt=true(ｺﾒﾝﾄ除外する) and useMD5=true(MD5計算する) 場合の処理
    419         * @og.rev 6.2.1.0 (2015/03/13) ﾃﾞｨﾚｸﾄﾘ以外からﾌｧｲﾙのみに対象を変更。
    420         * @og.rev 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、ｴﾗｰになる。
    421         * @og.rev 6.4.0.2 (2015/12/11) CommentLineParser 改造。
    422         * @og.rev 6.5.0.1 (2016/10/21) CharacterCodingException は、OgCharacterException に変換する。
    423         * @og.rev 8.1.0.4 (2022/01/28) 各行の空行はｶｳﾝﾄに含めないことにする。
    424         *
    425         * @param       file    行数を数えるﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄ
    426         * @param       ocFile  omitCmnt=trueの場合に、MD5計算する時の、仮出力ﾌｧｲﾙ(nullの場合は、無視)
    427         *
    428         * @return  long型の配列([0]が行数で、[1]が文字数)
    429         * @og.rtnNotNull
    430         */
    431        private long[] getLineCnt( final File file,final File ocFile ) {
    432                long lineCnt = 0L;              // 行数
    433                long charCnt = 0L;              // 文字数
    434
    435                final BufferedReader reader = FileUtil.getBufferedReader( file,encode );
    436
    437                // 5.7.7.1 (2014/06/13) omitCmnt=true(ｺﾒﾝﾄ除外する) and useMD5=true(MD5計算する) 場合の処理
    438                PrintWriter writer = null;
    439                if( ocFile != null ) { writer = FileUtil.getPrintWriter( ocFile ,encode ); }
    440
    441                // 6.4.0.2 (2015/12/11) CommentLineParser 改造
    442                final CommentLineParser clp = omitCmnt ? new CommentLineParser( FileInfo.getSUFIX( file ) ) : null;
    443                try {
    444                        // 6.2.1.0 (2015/03/13) ﾃﾞｨﾚｸﾄﾘ以外からﾌｧｲﾙのみに対象を変更。
    445                        if( file.isFile() ) {
    446                                String line ;
    447                                while((line = reader.readLine()) != null) {
    448                                        if( omitCmnt ) {
    449                                                line = clp.line( line );
    450                                                // 8.1.0.4 (2022/01/28) 各行の空行はｶｳﾝﾄに含めないことにする。
    451//                                              if( line == null ) { continue; }        // 戻り値が null の場合は、行として不成立
    452                                                if( line == null || line.isEmpty() ) { continue; }      // 戻り値が nullか 空行の場合は、含めない
    453                                                if( writer != null ) { writer.println( line ); }        // 5.7.7.1 (2014/06/13)
    454                                        }
    455
    456                                        lineCnt++;
    457                                        charCnt += line.length();
    458                                }
    459                        }
    460                }
    461                // 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、ｴﾗｰになる。
    462                catch( final CharacterCodingException ex ) {
    463                        final String errMsg = "文字のエンコード・エラーが発生しました。" + CR
    464                                                                +       "  ファイルのエンコードが指定のエンコードと異なります。" + CR
    465                                                                +       " [" + file.getPath() + "] , Encode=[" + encode + "]" ;
    466                        throw new OgCharacterException( errMsg,ex );    // 6.5.0.1 (2016/10/21)
    467                }
    468                catch( final IOException ex ) {
    469                        final String errMsg = "ファイルカウント中に例外が発生しました。" + CR
    470                                                                +       " [" + file.getPath() + "] , Encode=[" + encode + "]" ;
    471                        throw new OgRuntimeException( errMsg,ex );
    472                }
    473                finally {
    474                        Closer.ioClose( reader ) ;
    475                        Closer.ioClose( writer ) ;              // 5.7.7.1 (2014/06/13) ioClose は、引数が null なら無視します。
    476                }
    477
    478                return new long[] { lineCnt,charCnt };
    479        }
    480}