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.util.Argument; 020import org.opengion.fukurou.util.HybsFileFilter; 021import org.opengion.fukurou.system.LogWriter; 022 023import java.io.File; 024import java.util.Map ; 025import java.util.LinkedHashMap ; 026import java.util.Stack; 027 028/** 029 * Process_FileSearch は、指定のフォルダ以下のファイルを一覧する、FirstProcess 030 * インターフェースと、ChainProcess インターフェースの実装クラスです。 031 * 032 * Fileリストは、FileLineModel オブジェクトを使用します。 033 * ファイル属性(Level,File,Length,Modify,LineCnt,Biko,MD5) と、 034 * オプションで、FILEPATH,ADDRESS,FILENAME 属性を文字列で準備できます。 035 * 036 * 指定の条件に合致するファイルを検索し、LineModel のサブクラスである、 037 * FileLineModel オブジェクトを作成して、下流に渡します。 038 * FileLineModel オブジェクトには、ファイル属性(Level,File,Length,Modify) 039 * が設定されます。 040 * 041 * 引数文字列中にスペースを含む場合は、ダブルコーテーション("") で括って下さい。 042 * 引数文字列の 『=』の前後には、スペースは挟めません。必ず、-key=value の様に 043 * 繋げてください。 044 * 045 * ※ 6.3.1.1 (2015/07/10) 046 * ignoreCase の導入と同時に、初期値を、Grep , GrepChange , GrepChangeExcel と『異なる』 047 * true:区別しない にしました。 048 * これは、混乱する可能性が高いのですが、ファイル関連の検索において、通常は、大文字小文字の 049 * 区別なしで検索するのが多く、Grep の区別するケースとは異なると判断しました。 050 * 実際は、ignoreCase 属性を毎回記述したくないというのが、本当の所です。 051 * 052 * ※ 6.4.0.2 (2015/12/11) 053 * prefix,suffix,instr,equals に、("|"で複数指定可) の説明をJavaDocに追加。 054 * useDIR 属性に、onlyパラメータを追加[false:File/true:File+Dir/only:Dir]。 055 * ※ 7.2.6.0 (2020/06/30) 056 * useDIR 属性は廃止。 057 * 058 * @og.formSample 059 * Process_FileSearch -start=d:/ -suffix=jsp 060 * 061 * -start=開始フォルダ :検索を開始するフォルダ 062 * [ -ignoreCase=[true/false] ] :検索時に大文字小文字を区別しないかどうか(初期値:区別しない[true]) 063 * [ -prefix=接頭辞 ] :File・・・・,View・・・・,など、指定の接頭辞で始まるファイルを検索("|"で複数指定可) 064 * [ -unprefix=不接頭辞 ] :File・・・・,View・・・・,など、指定の接頭辞で始まらないファイルを検索("|"で複数指定可) 065 * [ -preDir=接頭辞フォルダ ] :(追加:7.2.6.0 (2020/06/30))File・・・・,View・・・・,など、指定の接頭辞で始まるフォルダを検索("|"で複数指定可) // 6.4.3.2 (2016/02/19) 066 * [ -unpreDir=不接頭辞フォルダ ] :(追加:7.2.6.0 (2020/06/30))File・・・・,View・・・・,など、指定の接頭辞で始まらないフォルダを検索("|"で複数指定可) // 7.2.6.0 (2020/06/30) 067 * [ -suffix=接尾辞 ] :.txt|.java|.jsp.... など、指定の接尾辞で終わるファイルを検索("|"で複数指定可) 068 * [ -unsuffix=不接尾辞 ] :.txt|.java|.jsp.... など、指定の接尾辞で終わらないファイルを検索("|"で複数指定可) 069 * [ -instr=部分文字列 ] :ファイル名と一致する部分文字列を指定("|"で複数指定可) 070 * [ -uninstr=不部分文字列 ] :ファイル名と一致しな部分文字列を指定("|"で複数指定可) 071 * [ -instrDir=部分文字列 ] :(追加:7.2.6.0 (2020/06/30))フォルダと一致する部分文字列を指定("|"で複数指定可) // 7.2.6.0 (2020/06/30) 072 * [ -uninstrDir=不部分文字列 ] :(追加:7.2.6.0 (2020/06/30))フォルダと一致しな部分文字列を指定("|"で複数指定可) // 7.2.6.0 (2020/06/30) 073 * [ -equals=一致 廃止 ] :ファイル名と一致する文字列を指定("|"で複数指定可) 7.2.7.0 (2020/08/07) 廃止 074 * [ -notequals=不一致 廃止 ] :ファイル名と一致しない文字列を指定("|"で複数指定可) 7.2.7.0 (2020/08/07) 廃止 075 * [ -fileEequals=一致 ] :ファイル名と一致する文字列を指定("|"で複数指定可) 7.2.7.0 (2020/08/07) 追加 076 * [ -unFileEquals=不一致 ] :ファイル名と一致しない文字列を指定("|"で複数指定可) 7.2.7.0 (2020/08/07) 追加 077 * [ -match=正規表現 ] :ファイル名と一致する正規表現を指定 078 * [ -unmatch=正規表現 ] :ファイル名と一致しない正規表現を指定 079 * [ -matchDir=正規表現 ] :(追加:7.2.6.0 (2020/06/30))フォルダと一致する正規表現を指定 // 7.2.6.0 (2020/06/30) 080 * [ -unmatchDir=不一致フォルダ ] :(追加:7.2.6.0 (2020/06/30))フォルダと一致しない正規表現を指定 // 7.2.6.0 (2020/06/30) 081 * [ -modify=YYYYMMDD ] :指定日付け以降に変更されたファイルを検索 082 * YYYYMMDD : YYYYMMDD 形式での指定日の 00:00:00 を基準時刻 083 * TODAY : 実行日の 00:00:00 を基準時刻 084 * YESTERDAY : 実行日前日の 00:00:00 を基準時刻 085 * LAST_WEEK : 実行日の先週(7日前) 00:00:00 を基準時刻 086 * MONTH : 実行月の 1日 00:00:00 を基準時刻 087 * LAST_MONTH : 実行前月の 同日 00:00:00 を基準時刻 088 * LAST_YEAR : 実行前年の 同月同日 00:00:00 を基準時刻 089 * [ -unmodify=YYYYMMDD ] :(追加:7.2.6.0 (2020/06/30))指定日付け以前に変更されたファイルを検索(形式はmodifyと同一) 090 * [ -useDIR=[false/true/only] ] :(廃止:7.2.6.0 (2020/06/30))判定をファイルだけでなく、ディレクトリでも行うかどうかを指定[false:File/true:File+Dir/only:Dir](初期値:false) 091 * [ -larger=サイズ(Byte) ] :ファイルの大きさが指定のバイト数と同じか大きいファイルを検索 092 * [ -smaller=サイズ(Byte) ] :ファイルの大きさが指定のバイト数より小さいファイルを検索 093 * [ -isHidden=[true/false] ] :true:HIDDENファイルのみ検索/false:NORMALファイルのみ検索(初期値:null) 094 * [ -maxLevel=最大階層数 ] :ディレクトリの階層を下がる最大数(初期値:256) 095 * [ -useLineCnt=行数計算 ] :ファイルの行数をカウントするかどうかを指定(初期値:false) 096 * [ -useMD5=MD5計算値 ] :ファイルのMD5計算を行うかどうかを指定(初期値:false) 097 * [ -useOmitCmnt=[false/true] ] :コメント部分を削除した行数と文字数計算を行うかどうかを指定(初期値:false) 098 * [ -useFilePath=[false/true] ] :FILEPATH,ADDRESS,FILENAME 属性を文字列で準備します(初期値:false) 099 * [ -modifyForm=日付フォーマット ] :MODIFY 属性のDate型から文字列に変換するフォーマットを指定します(初期値:null) 100 * [ -encode=エンコード名 ] :コメント削除時の文字数計算で利用するファイルのエンコード(初期値:JISAutoDetect) 101 * [ -inPath=入力共通パス ] :BIKO作成用のファイルパスから削除する部分(文字数のみ) 102 * [ -outPath=出力追加パス ] :BIKO作成用のファイルパスに追加する部分 103 * [ -errAbend=[true/false] ] :異常発生時に、処理を中断(true)するか、継続(false)するかを指定する(初期値:true[中断する]) 104 * [ -display=[false/true] ] :trueは、検索状況を表示します(初期値:false) 105 * [ -debug=[false/true] ] :デバッグ情報を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない]) 106 * 107 * @version 4.0 108 * @author Kazuhiko Hasegawa 109 * @since JDK5.0, 110 */ 111public class Process_FileSearch extends AbstractProcess implements FirstProcess , ChainProcess { 112 113 private Stack<FileListStack> dirs ; 114 private File file ; 115 private HybsFileFilter filter ; 116 private FileLineModel newData ; 117 private int level = 1; 118 119 private String startDir ; 120 private int maxLevel = 256; 121 private int inCount ; 122 private int outCount ; 123 private int inPathLen ; // 4.2.3.0 (2008/05/26) BIKO欄用 124 private String outPath ; // 4.3.1.1 (2008/08/23) BIKO欄用 125 private boolean errAbend = true; // 6.3.1.0 (2015/06/28) 中断する 126 private boolean display ; // false:表示しない 127 private boolean debug ; // 5.7.3.0 (2014/02/07) デバッグ情報 128 129 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 130 private static final Map<String,String> MUST_PROPARTY ; // [プロパティ]必須チェック用 Map 131 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 132 private static final Map<String,String> USABLE_PROPARTY ; // [プロパティ]整合性チェック Map 133 134 static { 135 MUST_PROPARTY = new LinkedHashMap<>(); 136 MUST_PROPARTY.put( "start", "検索を開始するフォルダ(必須)" ); 137 138 USABLE_PROPARTY = new LinkedHashMap<>(); 139 USABLE_PROPARTY.put( "ignoreCase" , "大文字小文字を区別しないかどうか(初期値:区別しない[true])" ); // 6.3.1.1 (2015/07/10) 140 USABLE_PROPARTY.put( "preDir" , "File・・・・,View・・・・,など、指定の接頭辞で始まるフォルダを検索" ); // 6.4.3.2 (2016/02/19) 141 USABLE_PROPARTY.put( "unpreDir" , "File・・・・,View・・・・,など、指定の接頭辞で始まらないフォルダを検索" ); // 7.2.6.0 (2020/06/30) 142 USABLE_PROPARTY.put( "prefix" , "File・・・・,View・・・・,など、指定の接頭辞で始まるファイルを検索" ); 143 USABLE_PROPARTY.put( "unprefix" , "File・・・・,View・・・・,など、指定の接頭辞で始まらないファイルを検索" ); 144 USABLE_PROPARTY.put( "suffix" , ".txt|.java|.jsp.... など、指定の接尾辞で終わるファイルを検索" ); 145 USABLE_PROPARTY.put( "unsuffix" , ".txt|.java|.jsp.... など、指定の接尾辞で終わらないファイルを検索" ); 146 USABLE_PROPARTY.put( "instr" , "ファイル名と一致する部分文字列を指定" ); 147 USABLE_PROPARTY.put( "uninstr" , "ファイル名と一致しない部分文字列を指定" ); 148 USABLE_PROPARTY.put( "instrDir" , "フォルダと一致する部分文字列を指定" ); // 7.2.6.0 (2020/06/30) 149 USABLE_PROPARTY.put( "uninstrDir" , "フォルダと一致しない部分文字列を指定" ); // 7.2.6.0 (2020/06/30) 150// USABLE_PROPARTY.put( "equals" , "ファイル名と一致する文字列を指定" ); // 7.2.7.0 (2020/08/07) 廃止 151// USABLE_PROPARTY.put( "notequals" , "ファイル名と一致しない文字列を指定" ); // 7.2.7.0 (2020/08/07) 廃止 152 USABLE_PROPARTY.put( "fileEquals" , "ファイル名と一致する文字列を指定" ); // 7.2.7.0 (2020/08/07) 追加 153 USABLE_PROPARTY.put( "unFileEquals" , "ファイル名と一致しない文字列を指定" ); // 7.2.7.0 (2020/08/07) 追加 154 USABLE_PROPARTY.put( "match" , "ファイル名と一致する正規表現を指定" ); 155 USABLE_PROPARTY.put( "unmatch" , "ファイル名と一致しない正規表現を指定" ); 156 USABLE_PROPARTY.put( "matchDir" , "フォルダと一致する正規表現を指定" ); // 7.2.6.0 (2020/06/30) 157 USABLE_PROPARTY.put( "unmatchDir" , "フォルダと一致しない正規表現を指定" ); // 7.2.6.0 (2020/06/30) 158 USABLE_PROPARTY.put( "modify" , "指定日付け以降に変更されたファイルを検索" + 159 CR + "YYYYMMDD : YYYYMMDD 形式での指定日の 00:00:00 を基準時刻" + 160 CR + "TODAY : 実行日の 00:00:00 を基準時刻" + 161 CR + "YESTERDAY : 実行日前日の 00:00:00 を基準時刻" + 162 CR + "LAST_WEEK : 実行日の先週(7日前) 00:00:00 を基準時刻" + 163 CR + "MONTH : 実行月の 1日 00:00:00 を基準時刻" + 164 CR + "LAST_MONTH : 実行前月の 同日 00:00:00 を基準時刻" + 165 CR + "LAST_YEAR : 実行前年の 同月同日 00:00:00 を基準時刻" 166 ); 167 USABLE_PROPARTY.put( "unmodify" , "指定日付け以前に変更されたファイルを検索" ); // 7.2.6.0 (2020/06/30) 168// USABLE_PROPARTY.put( "useDIR" , "判定をファイルだけでなく、ディレクトリでも行うかどうかを指定[false:File/true:File+Dir/only:Dir](初期値:false)" ); // 7.2.6.0 (2020/06/30) 廃止 169 USABLE_PROPARTY.put( "larger" , "ファイルの大きさが指定のバイト数と同じか大きいファイルを検索" ); 170 USABLE_PROPARTY.put( "smaller" , "ファイルの大きさが指定のバイト数より小さいファイルを検索" ); 171 USABLE_PROPARTY.put( "isHidden" , "true:HIDDENファイルのみ検索/false:NORMALファイルのみ検索(初期値:null)" ); 172 USABLE_PROPARTY.put( "maxLevel" , "ディレクトリの階層を下がる最大数(初期値:256)" ); 173 USABLE_PROPARTY.put( "useLineCnt" , "ファイルの行数をカウントするかどうかを指定(初期値:false)" ); 174 USABLE_PROPARTY.put( "useMD5" , "ファイルのMD5計算を行うかどうかを指定(初期値:false)" ); // 5.7.2.1 (2014/01/17) 175 USABLE_PROPARTY.put( "useOmitCmnt" , "コメント部分を削除した行数と文字数計算を行うかどうかを指定(初期値:false)" ); // 5.7.4.0 (2014/03/07) 176 USABLE_PROPARTY.put( "useFilePath" , "FILEPATH,ADDRESS,FILENAME 属性を文字列で準備します(初期値:false)" ); // 6.3.1.0 (2015/06/28) 177 USABLE_PROPARTY.put( "modifyForm" , "MODIFY 属性のDate型から文字列に変換するフォーマットを指定します(初期値:null)" ); // 6.3.1.1 (2015/07/10) 178 USABLE_PROPARTY.put( "encode" , "コメント削除時の文字数計算で利用するファイルのエンコード(初期値:JISAutoDetect)" ); // 5.7.4.0 (2014/03/07) 179 USABLE_PROPARTY.put( "inPath" , "BIKO作成用のファイルパスから削除する部分(文字数のみ)" ); 180 USABLE_PROPARTY.put( "outPath" , "BIKO作成用のファイルパスに追加する部分" ); 181 USABLE_PROPARTY.put( "errAbend" , "異常発生時に、処理を中断(true)するか、継続(false)するか" + 182 CR + "(初期値:true:中断する)" ); // 6.3.1.0 (2015/06/28) 183 USABLE_PROPARTY.put( "display" , "trueは、検索状況を表示します(初期値:false)" ); 184 USABLE_PROPARTY.put( "debug" , "デバッグ情報を標準出力に表示する(true)かしない(false)か" + 185 CR + "(初期値:false:表示しない)" ); // 5.7.3.0 (2014/02/07) デバッグ情報 186 } 187 188 /** 189 * デフォルトコンストラクター。 190 * このクラスは、動的作成されます。デフォルトコンストラクターで、 191 * super クラスに対して、必要な初期化を行っておきます。 192 * 193 */ 194 public Process_FileSearch() { 195 super( "org.opengion.fukurou.process.Process_FileSearch",MUST_PROPARTY,USABLE_PROPARTY ); 196 } 197 198 /** 199 * プロセスの初期化を行います。初めに一度だけ、呼び出されます。 200 * 初期処理(ファイルオープン、DBオープン等)に使用します。 201 * 202 * @og.rev 4.2.2.0 (2008/05/10) 行数カウントの使用有無 203 * @og.rev 4.3.1.1 (2008/08/23) BIKO 欄にoutPath 属性を追加します。 204 * @og.rev 5.1.2.0 (2010/01/01) useDIR 属性を追加します。 205 * @og.rev 5.7.2.1 (2014/01/17) useMD5 属性を追加します。 206 * @og.rev 5.7.4.0 (2014/03/07) useOmitCmnt,encode 属性を追加します。 207 * @og.rev 5.7.4.3 (2014/03/28) larger,smaller属性を文字列に変更 208 * @og.rev 5.7.5.0 (2014/04/04) isHidden属性を追加します。 209 * @og.rev 6.3.1.0 (2015/06/28) errAbend属性追加。 210 * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加 211 * @og.rev 6.3.1.1 (2015/07/10) メソッドチェーン化と、大文字/小文字の区別なし(ignoreCase=true)対応 212 * @og.rev 6.3.1.1 (2015/07/10) Modify のフォーマットを、指定可能にします。 213 * @og.rev 6.4.0.2 (2015/12/11) useDIR 属性に、onlyパラメータを追加します[false:File/true:File+Dir/only:Dir]。 214 * @og.rev 7.2.6.0 (2020/06/30) ディレクトリ処理を統一します。 215 * @og.rev 7.2.7.0 (2020/08/07) equals,notequals 廃止、fileEquals,unFileEquals 追加 216 * 217 * @param paramProcess データベースの接続先情報などを持っているオブジェクト 218 */ 219 public void init( final ParamProcess paramProcess ) { 220 final Argument arg = getArgument(); 221 222 startDir = arg.getProparty( "start" ); 223 224 final String inPath = arg.getProparty( "inPath" ); 225 if( inPath != null ) { inPathLen = inPath.length(); } 226 227 final boolean ignoreCase= arg.getProparty( "ignoreCase" ,true ); // 6.3.1.1 (2015/07/10) 228 final String preDir = arg.getProparty( "preDir" ); // 6.4.3.2 (2016/02/19) 229 final String unpreDir = arg.getProparty( "unpreDir" ); // 7.2.6.0 (2020/06/30) 230 final String prefix = arg.getProparty( "prefix" ); 231 final String unprefix = arg.getProparty( "unprefix" ); // 5.1.2.0 (2010/01/01) 追加 232 final String suffix = arg.getProparty( "suffix" ); 233 final String unsuffix = arg.getProparty( "unsuffix" ); // 5.1.2.0 (2010/01/01) 追加 234 final String instr = arg.getProparty( "instr" ); 235 final String uninstr = arg.getProparty( "uninstr" ); // 5.1.2.0 (2010/01/01) 追加 236 final String instrDir = arg.getProparty( "instrDir" ); // 7.2.6.0 (2020/06/30) 237 final String uninstrDir = arg.getProparty( "uninstrDir" ); // 7.2.6.0 (2020/06/30) 238// final String equals = arg.getProparty( "equals" ); // 7.2.7.0 (2020/08/07) 廃止 239// final String notequals = arg.getProparty( "notequals" ); // 5.1.2.0 (2010/01/01) 追加 // 7.2.7.0 (2020/08/07) 廃止 240 final String fileEquals = arg.getProparty( "fileEquals" ); // 7.2.7.0 (2020/08/07) 追加 241 final String unFileEquals = arg.getProparty( "unFileEquals" ); // 5.1.2.0 (2010/01/01) 追加 // 7.2.7.0 (2020/08/07) 追加 242 final String match = arg.getProparty( "match" ); 243 final String unmatch = arg.getProparty( "unmatch" ); 244 final String matchDir = arg.getProparty( "matchDir" ); // 7.2.6.0 (2020/06/30) 245 final String unmatchDir = arg.getProparty( "unmatchDir" ); // 7.2.6.0 (2020/06/30) 246 final String modify = arg.getProparty( "modify" ); 247 final String unmodify = arg.getProparty( "unmodify" ); // 7.2.6.0 (2020/06/30) 248 final String larger = arg.getProparty( "larger" ); 249 final String smaller = arg.getProparty( "smaller" ); 250 final String isHidden = arg.getProparty( "isHidden" ); // 5.7.5.0 (2014/04/04) 追加 251 maxLevel = arg.getProparty( "maxLevel",maxLevel); 252 outPath = arg.getProparty( "outPath" ); 253 // 4.2.2.0 (2008/05/10) 行数カウントの使用有無 254 final boolean useLineCnt = arg.getProparty( "useLineCnt",false ); 255 // 5.7.2.1 (2014/01/17) ファイルのMD5の計算有無 256 final boolean useMD5 = arg.getProparty( "useMD5",false ); 257 // 5.7.4.0 (2014/03/07) コメント部分を削除した行数と文字数計算を行うかどうか 258 final boolean useOmitCmnt = arg.getProparty( "useOmitCmnt",false ); 259 // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加 260 final boolean useFilePath = arg.getProparty( "useFilePath",false ); 261 // 6.3.1.1 (2015/07/10) MODIFY 属性のDate型から文字列に変換するフォーマットを指定します 262 final String modifyForm = arg.getProparty( "modifyForm",null ); 263 // 5.7.4.0 (2014/03/07) コメント削除時の文字数計算で利用するファイルのエンコード(初期値:JISAutoDetect) 264 final String encode = arg.getProparty( "encode" , "JISAutoDetect" ); 265 266// // 5.1.2.0 (2010/01/01) 判定をディレクトリでも行うかどうか 267// // 6.4.0.2 (2015/12/11) useDIR 属性に、onlyパラメータを追加します[false:File/true:File+Dir/only:Dir]。 268// // 7.2.6.0 (2020/06/30) useDIR属性 廃止 269// final String useDIR = arg.getProparty( "useDIR","false" ); 270 271 errAbend= arg.getProparty( "errAbend" , errAbend ); // 6.3.1.0 (2015/06/28) errAbend属性追加 272 display = arg.getProparty( "display" , display ); 273 debug = arg.getProparty( "debug" , debug ); // 5.7.3.0 (2014/02/07) デバッグ情報 274 275 // 6.3.1.1 (2015/07/10) メソッドチェーン化と、大文字/小文字の区別なし(ignoreCase=true)対応 276 // 7.2.6.0 (2020/06/30) 277// filter = new HybsFileFilter( useDIR,ignoreCase ) 278 filter = new HybsFileFilter( ignoreCase ) // 7.2.6.0 (2020/06/30) useDIR属性 廃止 279 .startsDir( preDir ) // 6.4.3.2 (2016/02/19) 280 .startsDir( unpreDir , true ) // 7.2.6.0 (2020/06/30) 281 .startsWith( prefix ) 282 .startsWith( unprefix , true ) 283 .endsWith( suffix ) 284 .endsWith( unsuffix , true ) 285 .instr( instr ) 286 .instr( uninstr , true ) 287 .instrDir( instrDir ) // 7.2.6.0 (2020/06/30) 288 .instrDir( uninstrDir , true ) // 7.2.6.0 (2020/06/30) 289// .fileEquals( equals ) // 7.2.7.0 (2020/08/07) 廃止 290// .fileEquals( notequals , true ) // 7.2.7.0 (2020/08/07) 廃止 291 .fileEquals( fileEquals ) // 7.2.7.0 (2020/08/07) 追加 292 .fileEquals( unFileEquals, true ) // 7.2.7.0 (2020/08/07) 追加 293 .matches( match ) 294 .matches( unmatch , true ) 295 .matchDir( matchDir ) // 7.2.6.0 (2020/06/30) 296 .matchDir( unmatchDir , true ) // 7.2.6.0 (2020/06/30) 297 .lastModified( modify ) 298 .lastModified( unmodify , true ) // 7.2.6.0 (2020/06/30) 299 .isLarger( larger ) // 5.7.4.3 (2014/03/28) larger,smaller属性を文字列に変更 300 .isSmaller( smaller ) 301 .isHidden( isHidden ); // 5.7.5.0 (2014/04/04) 追加 302 303 final File tempFile = new File( startDir ); 304 if( display ) { println( "start=[" + tempFile + "]" ); } // 5.7.3.0 (2014/02/07) 305 if( tempFile.isDirectory() ) { 306 dirs = new Stack<>(); 307 final File[] fileList = tempFile.listFiles( filter ); 308 dirs.push( new FileListStack( fileList, level ) ); 309 } 310 else { 311 dirs = new Stack<>(); 312 final File[] fileList = new File[] { tempFile }; 313 dirs.push( new FileListStack( fileList, level ) ); 314 } 315 316 newData = new FileLineModel( useLineCnt,useMD5,useOmitCmnt,useFilePath ); // 6.3.1.0 (2015/06/28) 317 newData.setEncode( encode ); 318 newData.setModifyForm( modifyForm ); // 6.3.1.1 (2015/07/10) 319 } 320 321 /** 322 * このデータの処理において、次の処理が出来るかどうかを問い合わせます。 323 * この呼び出し1回毎に、次のデータを取得する準備を行います。 324 * 325 * @og.rev 5.3.8.0 (2011/08/01) 処理中の状態を表示するための println を追加 326 * 327 * @return 処理できる:true / 処理できない:false 328 */ 329 @Override // FirstProcess 330 public boolean next() { 331 while( !dirs.empty() ) { 332 final FileListStack fStack = dirs.pop(); 333 334 level = fStack.getLevel(); 335 if( level > maxLevel ) { continue; } 336 337 final File[] fileList = fStack.getFileList(); 338 if( fileList == null ) { continue; } 339 340 int address = fStack.getAddress(); 341 for( ; address<fileList.length; address++ ) { 342 inCount++ ; 343 if( fileList[address].isDirectory() ) { 344 if( debug ) { println( "file Add=" + fileList[address].getAbsolutePath() ); } // 5.7.3.0 (2014/02/07) デバッグ情報 345 final File[] newList = fileList[address].listFiles( filter ); 346 dirs.push( new FileListStack( newList,level+1) ); 347 } 348 else { 349 file = fileList[address]; 350 if( debug ) { println( "file=" + file ); } // 5.7.3.0 (2014/02/07) デバッグ情報 351 fStack.setAddress( address+1 ); 352 dirs.push( fStack ); 353 return true; 354 } 355 } 356 } 357 return false; 358 } 359 360 /** 361 * 最初に、 行データである LineModel を作成します 362 * FirstProcess は、次々と処理をチェインしていく最初の行データを 363 * 作成して、後続の ChainProcess クラスに処理データを渡します。 364 * 365 * @og.rev 4.2.3.0 (2008/05/26) BIKO 欄に展開ファイル名を記述します。 366 * @og.rev 4.3.1.1 (2008/08/23) BIKO 欄にoutPath 属性を追加します。 367 * @og.rev 6.3.1.0 (2015/06/28) errAbend属性追加。 368 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 369 * 370 * @param rowNo 処理中の行番号 371 * 372 * @return 処理変換後のLineModel 373 */ 374 @Override // FirstProcess 375 public LineModel makeLineModel( final int rowNo ) { 376 outCount++ ; 377 // 6.3.1.0 (2015/06/28) 取りあえず、エラーの発生しそうな箇所で対応しておく。 378 try { 379 newData.setFileVals( level,file ); 380 } 381 catch( final RuntimeException ex ) { 382 // 6.3.1.1 (2015/07/10) throwExceptionメソッドを使用 383 final String errMsg = "rowNo=[" + rowNo + "] , file =[" + file + "]" ; 384 throwException( errMsg,ex,errAbend ); 385 } 386 387 // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 388 if( file == null ) { 389 final String errMsg = "#next() 実行しておかないと、file が初期化されません。" ; 390 throw new OgRuntimeException( errMsg ); 391 } 392 393 // 4.3.1.1 (2008/08/23) 394 String biko = null; 395 // 4.2.3.0 (2008/05/26) BIKO 欄追加 396 if( inPathLen > 0 ) { 397 biko = file.getAbsolutePath().substring( inPathLen ); 398 } 399 400 if( outPath != null ) { 401 if( biko == null ) { 402 biko = outPath + file.getName() ; 403 } 404 else { 405 biko = outPath + biko ; 406 } 407 } 408 if( biko != null ) { 409 newData.setBiko( biko ); 410 } 411 412 newData.setRowNo( rowNo ); 413 414 return newData; 415 } 416 417 /** 418 * 引数の LineModel を処理するメソッドです。 419 * 変換処理後の LineModel を返します。 420 * 後続処理を行わない場合(データのフィルタリングを行う場合)は、 421 * null データを返します。つまり、null データは、後続処理を行わない 422 * フラグの代わりにも使用しています。 423 * なお、変換処理後の LineModel と、オリジナルの LineModel が、 424 * 同一か、コピー(クローン)かは、各処理メソッド内で決めています。 425 * ドキュメントに明記されていない場合は、副作用が問題になる場合は、 426 * 各処理ごとに自分でコピー(クローン)して下さい。 427 * 428 * @param data オリジナルのLineModel 429 * 430 * @return 処理変換後のLineModel 431 */ 432 @Override // ChainProcess 433 public LineModel action( final LineModel data ) { 434 435 final FileLineModel fileData ; 436 if( data instanceof FileLineModel ) { 437 fileData = (FileLineModel)data ; 438 } 439 else { 440 // これは、プログラマーの問題なので、errAbend 対象外 441 final String errMsg = "データが FileLineModel オブジェクトではありません。" + CR ; 442 throw new OgRuntimeException( errMsg ); 443 } 444 445 if( debug ) { println( "Before:" + data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更 446 447 final File inFile = fileData.getFile() ; 448 final File[] fileList = inFile.listFiles( filter ); 449 450 LineModel rtn = null; 451 if( fileList != null && fileList.length > 0 ) { 452 rtn = data; 453 } 454 455 if( display && rtn != null ) { println( rtn.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更 456 return rtn ; 457 } 458 459 /** 460 * プロセスの終了を行います。最後に一度だけ、呼び出されます。 461 * 終了処理(ファイルクローズ、DBクローズ等)に使用します。 462 * 463 * @param isOK トータルで、OKだったかどうか[true:成功/false:失敗] 464 */ 465 public void end( final boolean isOK ) { 466 dirs = null; 467 file = null; 468 filter = null; 469 newData = null; 470 } 471 472 /** 473 * プロセスの処理結果のレポート表現を返します。 474 * 処理プログラム名、入力件数、出力件数などの情報です。 475 * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような 476 * 形式で出してください。 477 * 478 * @return 処理結果のレポート 479 */ 480 public String report() { 481 // 7.2.9.5 (2020/11/28) PMD:Consider simply returning the value vs storing it in local variable 'XXXX' 482 return "[" + getClass().getName() + "]" + CR 483// final String report = "[" + getClass().getName() + "]" + CR 484 + TAB + "Start Folder : " + startDir + CR 485 + TAB + "Search Count : " + inCount + CR 486 + TAB + "Output Count : " + outCount ; 487 488// return report ; 489 } 490 491 /** 492 * このクラスの使用方法を返します。 493 * 494 * @return このクラスの使用方法 495 * @og.rtnNotNull 496 */ 497 public String usage() { 498 final StringBuilder buf = new StringBuilder( 3000 ) 499 .append( "Process_FileSearch は、指定のフォルダ以下のファイルを一覧する、FirstProcess" ).append( CR ) 500 .append( "インターフェースと、ChainProcess インターフェースの実装クラスです。" ).append( CR ) 501 .append( CR ) 502 .append( "指定の条件に合致するファイルを検索し、ファイル属性(Level,File,Length,Modify)" ).append( CR ) 503 .append( "を元に、LineModelを作成し、下流に渡します。" ).append( CR ) 504 .append( CR ) 505 .append( "引数文字列中に空白を含む場合は、ダブルコーテーション(\"\") で括って下さい。" ).append( CR ) 506 .append( "引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に" ).append( CR ) 507 .append( "繋げてください。" ).append( CR ) 508 .append( CR ) 509 .append( " -start=開始フォルダ :検索を開始するフォルダ" ).append( CR ) 510 .append( "[ -ignoreCase=true/false]:大文字小文字を区別しないかどうか(初期値:しない[true])" ).append( CR ) 511 .append( "[ -preDir=接頭辞フォルダ ]:File・・・・,View・・・・,などの接頭辞で始まるフォルダ" ).append( CR ) // 6.4.3.2 (2016/02/19) 512 .append( "[ -prefix=接頭辞 ]:File・・・・,View・・・・,などの接頭辞で始まるファイル" ).append( CR ) 513 .append( "[ -unprefix=不接頭辞 ]:File・・・・,View・・・・,などの接頭辞で始まらないファイル" ).append( CR ) 514 .append( "[ -suffix=接尾辞 ]:.txt|.java|.jsp.... などの接尾辞で終わるファイル" ).append( CR ) 515 .append( "[ -unsuffix=不接尾辞 ]:.txt|.java|.jsp.... などの接尾辞で終わらないファイル" ).append( CR ) 516 .append( "[ -instr=部分文字列 ]:ファイル名と一致する部分文字列" ).append( CR ) 517 .append( "[ -uninstr=不部分文字列 ]:ファイル名と一致しな部分文字列" ).append( CR ) 518 .append( "[ -instrDir=部分文字列 ]:フォルダ名と一致する部分文字列" ).append( CR ) 519 .append( "[ -uninstrDir=不部分文字列 ]:フォルダ名と一致しな部分文字列" ).append( CR ) 520// .append( "[ -equals=一致 ]:ファイル名と一致する文字列" ).append( CR ) // 7.2.7.0 (2020/08/07) 廃止 521// .append( "[ -notequals=不一致 ]:ファイル名と一致しない文字列" ).append( CR ) // 7.2.7.0 (2020/08/07) 廃止 522 .append( "[ -fileEquals=一致 ]:ファイル名と一致する文字列" ).append( CR ) // 7.2.7.0 (2020/08/07) 追加 523 .append( "[ -unFileEquals=不一致 ]:ファイル名と一致しない文字列" ).append( CR ) // 7.2.7.0 (2020/08/07) 追加 524 .append( "[ -match=正規表現 ]:ファイル名と一致する正規表現" ).append( CR ) 525 .append( "[ -unmatch=正規表現 ]:ファイル名と一致しない正規表現" ).append( CR ) 526 .append( "[ -matchDir=正規表現 ]:フォルダ名と一致する正規表現" ).append( CR ) 527 .append( "[ -unmatchDir=正規表現 ]:フォルダ名と一致しない正規表現" ).append( CR ) 528 .append( "[ -modify=YYYYMMDD ]:指定日付け以降に変更されたファイル" ).append( CR ) 529 .append( " YYYYMMDD : YYYYMMDD 形式での指定日の 00:00:00 を基準時刻" ).append( CR ) 530 .append( " TODAY : 実行日の 00:00:00 を基準時刻" ).append( CR ) 531 .append( " YESTERDAY : 実行日前日の 00:00:00 を基準時刻" ).append( CR ) 532 .append( " LAST_WEEK : 実行日の先週(7日前) 00:00:00 を基準時刻" ).append( CR ) 533 .append( " MONTH : 実行月の 1日 00:00:00 を基準時刻" ).append( CR ) 534 .append( " LAST_MONTH : 実行前月の 同日 00:00:00 を基準時刻" ).append( CR ) 535 .append( " LAST_YEAR : 実行前年の 同月同日 00:00:00 を基準時刻" ).append( CR ) 536 .append( "[ -unmodify=YYYYMMDD ]:指定日付け以前に変更されたファイル" ).append( CR ) 537// .append( "[ -useDIR=[false/true/only]]:判定をディレクトリ名も含めて行うかどうか[false:File/true:File+Dir/only:Dir](初期値:false)").append( CR ) 538 .append( "[ -larger=サイズ(Byte) ]:大きさが指定のバイト数と同じか大きいファイル" ).append( CR ) 539 .append( "[ -smaller=サイズ(Byte) ]:大きさが指定のバイト数より小さいファイル" ).append( CR ) 540 .append( "[ -isHidden=[false/true]]:true:HIDDENのみ検索/false:NORMALのみ検索(初期値:null)" ).append( CR ) 541 .append( "[ -maxLevel=最大階層数 ]:ディレクトリの階層を下がる最大数(初期値:256)" ).append( CR ) 542 .append( "[ -useLineCnt=行数計算 ]:ファイルの行数をカウントするかどうか(初期値:false)" ).append( CR ) 543 .append( "[ -useMD5=MD5計算値 ]:ファイルのMD5計算を行うかどうかを指定(初期値:false)" ).append( CR ) 544 .append( "[ -useOmitCmnt=[false/true] ]:コメント部分を削除した行数と文字数計算を行うかどうか(初期値:false)" ).append( CR ) 545 .append( "[ -useFilePath=[false/true] ]:FILEPATH,ADDRESS,FILENAME 属性を準備(初期値:false)" ).append( CR ) 546 .append( "[ -modifyForm=日付フォーマット]:MODIFY 属性のDate型から文字列に変換するフォーマットを指定します(初期値:null)" ).append( CR ) 547 .append( "[ -inPath=入力共通パス ]:BIKO作成用のファイルパスから削除する文字列" ).append( CR ) 548 .append( "[ -outPath=出力追加パス ]:BIKO作成用のファイルパスに追加する文字列" ).append( CR ) 549 .append( "[ -display=[false/true] ]:trueは、検索状況を表示(初期値:false)" ).append( CR ) 550 .append( "[ -debug=[false/true] ]:trueは、デバッグ状況を表示(初期値:false)" ).append( CR ) 551 .append( CR ).append( CR ) 552 .append( getArgument().usage() ).append( CR ); 553 554 return buf.toString(); 555 } 556 557 /** 558 * このクラスは、main メソッドから実行できません。 559 * 560 * @param args コマンド引数配列 561 */ 562 public static void main( final String[] args ) { 563 LogWriter.log( new Process_FileSearch().usage() ); 564 } 565 566 /** 567 * このクラスはファイルをスタックを使用して展開する場合の 568 * 個々の状態を保持する為のクラスです。 569 * 570 * @version 4.0 571 * @author Kazuhiko Hasegawa 572 * @since JDK5.0, 573 */ 574 private static final class FileListStack { 575 private int address ; 576 private final File[] files; 577 private final int level; 578 579 /** 580 * コンストラクター 581 * 初期値を設定します。 582 * ファイルの配列については、コピーせずそのまま内部配列にセットしています。 583 * 584 * @param files ファイルの配列(ファイルリスト) 585 * @param level レベル(指定のstartフォルダからの階層数) 586 */ 587 FileListStack( final File[] files,final int level ) { 588 this.files = files; 589 this.address = 0; 590 this.level = level; 591 } 592 593 /** 594 * ファイルリストのアドレスを設定します。 595 * スタックから取り出した後、配列を前回の続きからサーチする場合に使用します。 596 * 597 * @param address ファイルリストのアドレス 598 */ 599 /* default */ void setAddress( final int address ) { 600 this.address = address; 601 } 602 603 /** 604 * ファイルリストのアドレスを取り出します。 605 * 606 * @return ファイルリストのアドレス 607 */ 608 /* default */ int getAddress() { 609 return address; 610 } 611 612 /** 613 * ファイルリストを取り出します。 614 * ファイルの配列については、コピーせずそのまま内部配列を返しています。 615 * 616 * @return ファイルリスト配列 617 */ 618 /* default */ File[] getFileList() { 619 return files; 620 } 621 622 /** 623 * 階層レベルを取り出します。 624 * 625 * @return レベル 626 */ 627 /* default */ int getLevel() { 628 return level; 629 } 630 } 631}