    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         *
    240         * @param       level   ﾌｧｲﾙのﾃﾞｨﾚｸﾄﾘ階層
    241         * @param       file    ﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄ
    242         */
    243        public void setFileVals( final int level, final File file ) {
    244                setValue( LEVEL  ,Integer.valueOf( level ) );
    245                setValue( FILE   ,file );
    246                setValue( MODIFY ,DateSet.getDate( file.lastModified(),modifyForm ) );                                  // 6.3.1.1 (2015/07/10)
    247
    248                // 5.7.7.1 (2014/06/13) omitCmnt=true(ｺﾒﾝﾄ除外する) and useMD5=true(MD5計算する) 場合の処理
    249                // 別にｺﾒﾝﾄ除去されたﾌｧｲﾙを作成して､それの MD5 を求める｡
    250                File ocFile = null;
    251                if( omitCmnt && useMD5 ) {
    252                        try {
    253                                ocFile = File.createTempFile( "temp",".tmp" );
    254                                ocFile.deleteOnExit();                                                          // 一応､このﾒｿｯﾄﾞ内で削除しますが､念のため｡
    255                        }
    256                        catch( final IOException ex ) {
    257                                final String errMsg = "ｺﾒﾝﾄ除外のMD5計算用 temp ﾌｧｲﾙの作成に失敗しました｡" + ex.getMessage() ;
    258                                throw new OgRuntimeException( errMsg,ex );
    259                        }
    260                }
    261
    262                if( useLineCnt || omitCmnt ) {
    263                        final long[] cntVals = getLineCnt( file,ocFile );                       // 5.7.7.1 (2014/06/13) 出力ﾌｧｲﾙを渡します｡
    264                        setValue( LINECNT ,String.valueOf( cntVals[0] ) );
    265                        setValue( LENGTH  ,Long.valueOf(   cntVals[1] ) );
    266                }
    267                else {
    268                        setValue( LENGTH  ,Long.valueOf( file.length() ) );
    269                }
    270
    271                // 5.7.2.1 (2014/01/17) MD5計算がtrue で､かつ､ﾌｧｲﾙの場合､MD5 計算を行います｡
    272                if( useMD5 && file.isFile() ) {
    273                        // 5.7.7.1 (2014/06/13) omitCmnt を考慮したMD5計算
    274                        if( ocFile == null ) {
    275                                setValue( MD5 ,HybsCryptography.getMD5( file ) );
    276                        }
    277                        else {
    278                                setValue( MD5 ,HybsCryptography.getMD5( ocFile ) );
    279                                // 6.0.2.4 (2014/10/17) RV  java.io.File.delete() の例外的戻り値を無視しています｡
    280                                // 6.2.1.0 (2015/03/13) ﾌｧｲﾙの削除に失敗するため､削除しない｡
    281                        }
    282                }
    283
    284                // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
    285                if( useFilePath ) {
    286                        // FILEPATH は､正規のﾊﾟｽ名文字列 を求めるが､ｴﾗｰ時は､絶対ﾊﾟｽ名文字列 にする｡
    287                        try {
    288                                setValue( FILEPATH      , file.getCanonicalPath() );    // 正規のﾊﾟｽ名文字列
    289                        }
    290                        catch( final IOException ex ) {
    291                                setValue( FILEPATH      , file.getAbsolutePath() );             // 絶対ﾊﾟｽ名文字列
    292                        }
    293
    294                        // ADDRESS は､親の名前なので､直ﾌｫﾙﾀﾞ名になる｡
    295                        final File parent = file.getParentFile();
    296                        if( parent != null ) {
    297                                setValue( ADDRESS       ,parent.getName() );
    298                        }
    299
    300                        setValue( FILENAME      ,file.getName() );
    301                }
    302        }
    303
    304        /**
    305         * ｺﾒﾝﾄ削除時の文字数計算で利用するﾌｧｲﾙのｴﾝｺｰﾄﾞをｾｯﾄします｡
    306         * 初期値:JISAutoDetect
    307         *
    308         * @og.rev 5.7.4.0 (2014/03/07) 新規追加
    309         *
    310         * @param       encode  ｺﾒﾝﾄ削除時の文字数計算で利用するﾌｧｲﾙのｴﾝｺｰﾄﾞ
    311         */
    312        public void setEncode( final String encode ) {
    313                this.encode = encode;
    314        }
    315
    316        /**
    317         * File属性値をｾｯﾄします｡
    318         *
    319         * @param       file    ﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄ
    320         */
    321        public void setFile( final File file ) {
    322                setValue( FILE,file );
    323        }
    324
    325        /**
    326         * ﾌｧｲﾙを取得します｡
    327         *
    328         * @return      ﾌｧｲﾙ
    329         */
    330        public File getFile() {
    331                return (File)getValue( FILE );
    332        }
    333
    334        /**
    335         * 備考情報属性値をｾｯﾄします｡
    336         *
    337         * @og.rev 4.2.2.0 (2008/05/10) 行数ｶｳﾝﾄの使用有無
    338         *
    339         * @param       biko    備考情報
    340         */
    341        public void setBiko( final String biko ) {
    342                setValue( BIKO,biko );
    343        }
    344
    345        /**
    346         * ﾚﾍﾞﾙ File属性値を取得します｡
    347         *
    348         * @return      ﾌｧｲﾙのﾃﾞｨﾚｸﾄﾘ階層
    349         */
    350        public int getLevel() {
    351                return ((Integer)getValue( LEVEL )).intValue();
    352        }
    353
    354        /**
    355         * ﾌｧｲﾙｻｲｽﾞ File属性値を取得します｡
    356         *
    357         * @return      ﾌｧｲﾙｻｲｽﾞ
    358         */
    359        public long getLength() {
    360                return ((Long)getValue( LENGTH )).longValue();
    361        }
    362
    363        /**
    364         * 更新日時(Modify) のﾌｫｰﾏｯﾄを､指定します｡
    365         *
    366         * ここで指定しない場合は､"yyyy/MM/dd HH:mm:ss" になります｡
    367         * Date型で変換できないようなﾌｫｰﾑを指定した場合は､実行時に
    368         * ｴﾗｰになりますので､ご注意ください｡
    369         *
    370         * @og.rev 6.3.1.1 (2015/07/10) Modify のﾌｫｰﾏｯﾄを､指定可能にします｡
    371         *
    372         * @param       form 更新日時のﾌｫｰﾏｯﾄ
    373         * @see         java.text.SimpleDateFormat
    374         */
    375        public void setModifyForm( final String form ) {
    376                if( form != null && !form.isEmpty() ) {
    377                        modifyForm = form;
    378                }
    379        }
    380
    381        /**
    382         * 更新日時 File属性値を取得します｡
    383         *
    384         * @return      更新日時(yyyy/MM/dd HH:mm:ss)
    385         */
    386        public String getModify() {
    387                return (String)getValue( MODIFY );
    388        }
    389
    390        /**
    391         * MD5 File属性値を取得します｡
    392         * ただし､useMD5 が true でないと値は返しません｡
    393         *
    394         * @og.rev 5.7.2.1 (2014/01/17) 新規追加(MD5対応)
    395         *
    396         * @return      MD5の値
    397         */
    398        public String getMD5() {
    399                return (String)getValue( MD5 );
    400        }
    401
    402        /**
    403         * 行数と文字数を取得します｡
    404         * 行数ｶｳﾝﾄとﾌｧｲﾙの文字数ｶｳﾝﾄ(ﾊﾞｲﾄ数ではありません)を行います｡
    405         * ※ useLineCnt=false の場合のLength(文字数)は､File#length() ﾒｿｯﾄﾞで求めます｡
    406         *    一方､useLineCnt=true にすると､行単位に､String#length() を加算するため､
    407         *    先のLength(文字数)値とは異なりますのでご注意ください｡
    408         *
    409         * 結果は､long型の配列で返します｡[0]が行数で､[1]が文字数です｡
    410         * omitCmnt 属性を使用した場合は､ｺﾒﾝﾄ部分を削除した行数と文字数を求めます｡
    411         * これは､/&#042; から &#042;/ の間､&#47;&#47; から改行までです｡
    412         * ただし､&#034;(二重引用符)で囲まれた文字列は､ｺﾒﾝﾄとみなしません｡
    413         *
    414         * @og.rev 5.7.4.0 (2014/03/07) 行数ｶｳﾝﾄとﾌｧｲﾙの文字数ｶｳﾝﾄを行う｡
    415         * @og.rev 5.7.7.1 (2014/06/13) omitCmnt=true(ｺﾒﾝﾄ除外する) and useMD5=true(MD5計算する) 場合の処理
    416         * @og.rev 6.2.1.0 (2015/03/13) ﾃﾞｨﾚｸﾄﾘ以外からﾌｧｲﾙのみに対象を変更｡
    417         * @og.rev 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで､ｴﾗｰになる｡
    418         * @og.rev 6.4.0.2 (2015/12/11) CommentLineParser 改造｡
    419         * @og.rev 6.5.0.1 (2016/10/21) CharacterCodingException は､OgCharacterException に変換する｡
    420         * @og.rev 8.1.0.4 (2022/01/28) 各行の空行はｶｳﾝﾄに含めないことにする｡
    421         *
    422         * @param       file    行数を数えるﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄ
    423         * @param       ocFile  omitCmnt=trueの場合に､MD5計算する時の､仮出力ﾌｧｲﾙ(nullの場合は､無視)
    424         *
    425         * @return  long型の配列([0]が行数で､[1]が文字数)
    426         * @og.rtnNotNull
    427         */
    428        private long[] getLineCnt( final File file,final File ocFile ) {
    429                long lineCnt = 0L;              // 行数
    430                long charCnt = 0L;              // 文字数
    431
    432                final BufferedReader reader = FileUtil.getBufferedReader( file,encode );
    433
    434                // 5.7.7.1 (2014/06/13) omitCmnt=true(ｺﾒﾝﾄ除外する) and useMD5=true(MD5計算する) 場合の処理
    435                PrintWriter writer = null;
    436                if( ocFile != null ) { writer = FileUtil.getPrintWriter( ocFile ,encode ); }
    437
    438                // 6.4.0.2 (2015/12/11) CommentLineParser 改造
    439                final CommentLineParser clp = omitCmnt ? new CommentLineParser( FileInfo.getSUFIX( file ) ) : null;
    440                try {
    441                        // 6.2.1.0 (2015/03/13) ﾃﾞｨﾚｸﾄﾘ以外からﾌｧｲﾙのみに対象を変更｡
    442                        if( file.isFile() ) {
    443                                String line ;
    444                                while((line = reader.readLine()) != null) {
    445                                        if( omitCmnt ) {
    446                                                line = clp.line( line );
    447                                                // 8.1.0.4 (2022/01/28) 各行の空行はｶｳﾝﾄに含めないことにする｡
    448//                                              if( line == null ) { continue; }        // 戻り値が null の場合は､行として不成立
    449                                                if( line == null || line.isEmpty() ) { continue; }      // 戻り値が nullか 空行の場合は､含めない
    450                                                if( writer != null ) { writer.println( line ); }        // 5.7.7.1 (2014/06/13)
    451                                        }
    452
    453                                        lineCnt++;
    454                                        charCnt += line.length();
    455                                }
    456                        }
    457                }
    458                // 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで､ｴﾗｰになる｡
    459                catch( final CharacterCodingException ex ) {
    460                        final String errMsg = "文字のｴﾝｺｰﾄﾞ･ｴﾗｰが発生しました｡" + CR
    461                                                                +       "  ﾌｧｲﾙのｴﾝｺｰﾄﾞが指定のｴﾝｺｰﾄﾞと異なります｡" + CR
    462                                                                +       " [" + file.getPath() + "] , Encode=[" + encode + "]" ;
    463                        throw new OgCharacterException( errMsg,ex );    // 6.5.0.1 (2016/10/21)
    464                }
    465                catch( final IOException ex ) {
    466                        final String errMsg = "ﾌｧｲﾙｶｳﾝﾄ中に例外が発生しました｡" + CR
    467                                                                +       " [" + file.getPath() + "] , Encode=[" + encode + "]" ;
    468                        throw new OgRuntimeException( errMsg,ex );
    469                }
    470                finally {
    471                        Closer.ioClose( reader ) ;
    472                        Closer.ioClose( writer ) ;              // 5.7.7.1 (2014/06/13) ioClose は､引数が null なら無視します｡
    473                }
    474
    475                return new long[] { lineCnt,charCnt };
    476        }
    477}