2 * Copyright (c) 2009 The openGion Project.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 * either express or implied. See the License for the specific language
14 * governing permissions and limitations under the License.
16 package org.opengion.fukurou.process;
18 import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29)
19 import org.opengion.fukurou.system.OgCharacterException ; // 6.5.0.1 (2016/10/21)
20 import org.opengion.fukurou.system.DateSet; // 6.4.2.0 (2016/01/29)
21 import org.opengion.fukurou.system.Closer;
22 import org.opengion.fukurou.util.FileUtil;
23 import org.opengion.fukurou.util.CommentLineParser;
24 import org.opengion.fukurou.util.FileInfo; // 6.4.0.2 (2015/12/11)
25 import org.opengion.fukurou.security.HybsCryptography ; // 5.7.2.1 (2014/01/17)
26 import static org.opengion.fukurou.system.HybsConst.CR; // 6.3.1.0 (2015/06/28)
29 import java.io.BufferedReader;
30 import java.io.PrintWriter;
31 import java.io.IOException;
32 import java.nio.charset.CharacterCodingException; // 6.3.1.0 (2015/06/28)
35 * FileLineModel は、LineModel を継承した ファイルリスト専用の
38 * FileLineModel オブジェクトには、ファイル属性(Level,File,Length,Modify,LineCnt,Biko,MD5)
40 * オプションで、FILEPATH,ADDRESS,FILENAME 属性を文字列で準備できます。(6.3.1.0 (2015/06/28))
41 * ADDRESS は、指定ファイルの親フォルダ。FILENAME はファイル名。FILEPATH は、ファイル名を含む
43 * ※ 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
44 * この、新しい属性に、値をセットする場合は、useFilePath="true" をセットしてください。
45 * ※ 6.3.1.1 (2015/07/10) Modify のフォーマット(modifyForm)を、指定可能にします。
46 * これは、Date型のまま、扱いたい所だが、文字列化しています。
47 * 初期値は、"yyyy/MM/dd HH:mm:ss" です。
49 * LineCnt と、MD5 は、それぞれ、計算するかどうかのフラグを設定する必要があります。
51 * ※ useLineCnt=false の場合のLength(文字数)は、File#length() メソッドで求めます。
52 * 一方、useLineCnt=true にすると、行単位に、String#length() を加算するため、
53 * 先のLength(文字数)値とは異なりますのでご注意ください。
55 * omitCmnt=true にすると、コメント部分を削除した行数と文字数を求めます。
56 * これは、/* から */ の間、// から改行までです。
57 * ただし、"(二重引用符)で囲まれた文字列は、コメントとみなしません。
59 * 8.1.0.4 (2022/01/28)
60 * さらに、各行の空行はカウントに含めないことにします。
62 * データの1行分を FileLineModel に割り当てます。
63 * カラム番号は、0 から始まります。カラム名よりカラム番号を求める場合に、
65 * カラム番号が -1 の場合は、処理を行いません。
67 * 注意:このクラスは、同期処理されていません。
70 * @author Kazuhiko Hasegawa
73 public class FileLineModel extends LineModel {
74 // 5.7.2.1 (2014/01/17) MD5 項目追加
75 // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
76 private static final String[] KEYS = { "Level","File","Length","Modify","LineCnt","Biko","MD5","FILEPATH","ADDRESS","FILENAME" };
78 private static final int LEVEL = 0;
79 private static final int FILE = 1;
80 private static final int LENGTH = 2;
81 private static final int MODIFY = 3;
82 private static final int LINECNT = 4;
83 private static final int BIKO = 5;
84 private static final int MD5 = 6; // 5.7.2.1 (2014/01/17)
85 private static final int FILEPATH = 7; // 6.3.1.0 (2015/06/28)
86 private static final int ADDRESS = 8; // 6.3.1.0 (2015/06/28)
87 private static final int FILENAME = 9; // 6.3.1.0 (2015/06/28)
89 private final boolean useLineCnt ;
90 private final boolean useMD5 ; // 5.7.2.1 (2014/01/17) MD5 項目追加
91 private final boolean omitCmnt ; // 5.7.4.0 (2014/03/07) コメント除外の可否(true:除外する)
92 private final boolean useFilePath ; // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性を使う場合は、true
93 private String encode = "JISAutoDetect"; // 5.7.4.0 (2014/03/07) コメント削除時の文字数計算で利用するファイルのエンコード
94 private String modifyForm = "yyyy/MM/dd HH:mm:ss" ; // 6.3.1.1 (2015/07/10)
98 * useLineCnt=false , useMD5=false , omitCmnt=false で初期化されます。
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 属性追加
105 public FileLineModel() {
106 this( false,false,false,false ); // 6.3.1.0 (2015/06/28)
110 * ラインカウントの有無を指定した、コンストラクターです。
111 * useMD5=false , omitCmnt=false で初期化されます。
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 属性追加
118 * @param isLineCnt 行数カウントの使用有無
120 public FileLineModel( final boolean isLineCnt ) {
121 this( isLineCnt,false,false,false ); // 6.3.1.0 (2015/06/28)
125 * ラインカウントの有無と、MD5計算の有無を指定した、コンストラクターです。
126 * omitCmnt=false で初期化されます。
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 属性追加。
132 * @param isLineCnt 行数カウントの使用有無
133 * @param isMD5 ファイルのMD5の使用有無
135 public FileLineModel( final boolean isLineCnt,final boolean isMD5 ) {
136 this( isLineCnt,isMD5,false,false ); // 6.3.1.0 (2015/06/28)
140 * ラインカウントの有無と、MD5計算の有無と、コメント除外の可否を指定した、コンストラクターです。
142 * @og.rev 5.7.4.0 (2014/03/07) コメント除外の可否(true:除外する)
143 * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
145 * @param isLineCnt 行数カウントの使用有無
146 * @param isMD5 ファイルのMD5の使用有無
147 * @param isOmit コメント除外の可否(true:除外する)
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 属性追加
154 * ラインカウントの有無と、MD5計算の有無と、コメント除外の可否と、追加属性可否を指定した、コンストラクターです。
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
160 * @param isLineCnt 行数カウントの使用有無
161 * @param isMD5 ファイルのMD5の使用有無
162 * @param isOmit コメント除外の可否(true:除外する)
163 * @param isPath FILEPATH,ADDRESS,FILENAME 属性の可否(true:使用する)
165 public FileLineModel( final boolean isLineCnt,final boolean isMD5,final boolean isOmit,final boolean isPath ) {
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)
176 * LineModel を元に、FileLineModel を構築します。
177 * これは、一旦ファイル等にセーブされた FileLineModel 形式を
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
185 * @param model 元のLineModel
187 public FileLineModel( final LineModel model ) {
189 // 4.3.4.4 (2009/01/01)
190 init( model.getNames() );
192 final Object[] obj = model.getValues();
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] );
199 final String cnt = (String)obj[LINECNT] ;
200 useLineCnt = cnt != null && cnt.length() > 0 && ! "null".equalsIgnoreCase( cnt ) ;
201 if( useLineCnt ) { setValue( LINECNT ,cnt ); }
203 setValue( BIKO ,(String)obj[BIKO] );
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 ); }
210 omitCmnt = false; // 5.7.4.0 (2014/03/07) 既存の LineModel から取得できないので、強制設定します。
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 ) ;
218 setValue( FILEPATH ,path );
219 if( obj.length > ADDRESS ) { setValue( ADDRESS ,(String)obj[ADDRESS] ); }
220 if( obj.length > FILENAME ) { setValue( FILENAME ,(String)obj[FILENAME] ); }
230 * LEVEL,FILE,LENGTH,MODIFY,LINECNT,MD5 の各属性を設定します。
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 メソッドに変更
241 * @param level ファイルのディレクトリ階層
242 * @param file ファイルオブジェクト
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)
249 // 5.7.7.1 (2014/06/13) omitCmnt=true(コメント除外する) and useMD5=true(MD5計算する) 場合の処理
250 // 別にコメント除去されたファイルを作成して、それの MD5 を求める。
252 if( omitCmnt && useMD5 ) {
254 ocFile = File.createTempFile( "temp",".tmp" );
255 ocFile.deleteOnExit(); // 一応、このメソッド内で削除しますが、念のため。
257 catch( final IOException ex ) {
258 final String errMsg = "コメント除外のMD5計算用 temp ファイルの作成に失敗しました。" + ex.getMessage() ;
259 throw new OgRuntimeException( errMsg,ex );
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] ) );
269 setValue( LENGTH ,Long.valueOf( file.length() ) );
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 ) );
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) ファイルの削除に失敗するため、削除しない。
287 // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
289 // FILEPATH は、正規のパス名文字列 を求めるが、エラー時は、絶対パス名文字列 にする。
291 setValue( FILEPATH , file.getCanonicalPath() ); // 正規のパス名文字列
293 catch( final IOException ex ) {
294 setValue( FILEPATH , file.getAbsolutePath() ); // 絶対パス名文字列
297 // ADDRESS は、親の名前なので、直フォルダ名になる。
298 final File parent = file.getParentFile();
299 if( parent != null ) {
300 setValue( ADDRESS ,parent.getName() );
303 setValue( FILENAME ,file.getName() );
308 * コメント削除時の文字数計算で利用するファイルのエンコードをセットします。
311 * @og.rev 5.7.4.0 (2014/03/07) 新規追加
313 * @param encode コメント削除時の文字数計算で利用するファイルのエンコード
315 public void setEncode( final String encode ) {
316 this.encode = encode;
322 * @param file ファイルオブジェクト
324 public void setFile( final File file ) {
325 setValue( FILE,file );
333 public File getFile() {
334 return (File)getValue( FILE );
340 * @og.rev 4.2.2.0 (2008/05/10) 行数カウントの使用有無
344 public void setBiko( final String biko ) {
345 setValue( BIKO,biko );
349 * レベル File属性値を取得します。
351 * @return ファイルのディレクトリ階層
353 public int getLevel() {
354 return ((Integer)getValue( LEVEL )).intValue();
358 * ファイルサイズ File属性値を取得します。
362 public long getLength() {
363 return ((Long)getValue( LENGTH )).longValue();
367 * 更新日時(Modify) のフォーマットを、指定します。
369 * ここで指定しない場合は、"yyyy/MM/dd HH:mm:ss" になります。
370 * Date型で変換できないようなフォームを指定した場合は、実行時に
371 * エラーになりますので、ご注意ください。
373 * @og.rev 6.3.1.1 (2015/07/10) Modify のフォーマットを、指定可能にします。
375 * @param form 更新日時のフォーマット
376 * @see java.text.SimpleDateFormat
378 public void setModifyForm( final String form ) {
379 if( form != null && !form.isEmpty() ) {
385 * 更新日時 File属性値を取得します。
387 * @return 更新日時(yyyy/MM/dd HH:mm:ss)
389 public String getModify() {
390 return (String)getValue( MODIFY );
395 * ただし、useMD5 が true でないと値は返しません。
397 * @og.rev 5.7.2.1 (2014/01/17) 新規追加(MD5対応)
401 public String getMD5() {
402 return (String)getValue( MD5 );
407 * 行数カウントとファイルの文字数カウント(バイト数ではありません)を行います。
408 * ※ useLineCnt=false の場合のLength(文字数)は、File#length() メソッドで求めます。
409 * 一方、useLineCnt=true にすると、行単位に、String#length() を加算するため、
410 * 先のLength(文字数)値とは異なりますのでご注意ください。
412 * 結果は、long型の配列で返します。[0]が行数で、[1]が文字数です。
413 * omitCmnt 属性を使用した場合は、コメント部分を削除した行数と文字数を求めます。
414 * これは、/* から */ の間、// から改行までです。
415 * ただし、"(二重引用符)で囲まれた文字列は、コメントとみなしません。
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) 各行の空行はカウントに含めないことにする。
425 * @param file 行数を数えるファイルオブジェクト
426 * @param ocFile omitCmnt=trueの場合に、MD5計算する時の、仮出力ファイル(nullの場合は、無視)
428 * @return long型の配列([0]が行数で、[1]が文字数)
431 private long[] getLineCnt( final File file,final File ocFile ) {
432 long lineCnt = 0L; // 行数
433 long charCnt = 0L; // 文字数
435 final BufferedReader reader = FileUtil.getBufferedReader( file,encode );
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 ); }
441 // 6.4.0.2 (2015/12/11) CommentLineParser 改造
442 final CommentLineParser clp = omitCmnt ? new CommentLineParser( FileInfo.getSUFIX( file ) ) : null;
444 // 6.2.1.0 (2015/03/13) ディレクトリ以外からファイルのみに対象を変更。
445 if( file.isFile() ) {
447 while((line = reader.readLine()) != null) {
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)
457 charCnt += line.length();
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)
468 catch( final IOException ex ) {
469 final String errMsg = "ファイルカウント中に例外が発生しました。" + CR
470 + " [" + file.getPath() + "] , Encode=[" + encode + "]" ;
471 throw new OgRuntimeException( errMsg,ex );
474 Closer.ioClose( reader ) ;
475 Closer.ioClose( writer ) ; // 5.7.7.1 (2014/06/13) ioClose は、引数が null なら無視します。
478 return new long[] { lineCnt,charCnt };