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