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 */
016 package org.opengion.fukurou.process;
017
018 import org.opengion.fukurou.util.Argument;
019 import org.opengion.fukurou.util.FileUtil;
020 import org.opengion.fukurou.util.Closer ;
021 import org.opengion.fukurou.util.LogWriter;
022
023 import java.util.Map ;
024 import java.util.LinkedHashMap ;
025
026 import java.io.File;
027 import java.io.PrintWriter;
028 import java.io.BufferedReader;
029 import java.io.IOException;
030
031 /**
032 * Process_FileCopy は、上流から受け取っ?FileLineModel を??る?
033 * ChainProcess インターフェースの実?ラスです?
034 *
035 * 上流から受け取っ?FileLineModel の ファイルから、inPath の共通パス
036 * 以下?ファイルを?outPath の共通パス以下にコピ?します?
037 * コピ?の種類?、バイナリか??ストで、テキスト?場合?、エンコー?
038 * 変換も行うことが可能です?
039 * inPath と outPath が同じ?また?、outPath が未設定?場合?、?力と出力が
040 * 同じです?で、???身のエンコード変換処?行うことになります?
041 *
042 * コピ?されるファイルのファイル名?、?力ファイル名と同?す?保存される
043 * フォル?異なります?(同?することも可能です?)
044 *
045 * 上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク?
046 * である、Process_FileSearch を使用するのが?便利です?それ以外?クラス?
047 * 使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡?
048 * できれば、使用可能です?
049 *
050 * 引数??中に空白を含??合?、ダブルコー??ション("") で括って下さ??
051 * 引数??の ?』?前後には、空白は挟めません。??key=value の様に
052 * 繋げてください?
053 *
054 * @og.formSample
055 * Process_FileCopy -inPath=入力?通パス -inEncode=Windows-31J -outPath=出力?通パス -outEncode=UTF-8
056 *
057 * -inPath=入力?通パス ?上流で検索されたファイルパスの共通部?
058 * [ -inEncode=入力エンコー? ] ??力ファイルのエンコードタイ?
059 * [ -outPath=出力?通パス ] ??力するファイルパスの共通部?
060 * [ -outEncode=出力エンコー? ] ??力ファイルのエンコードタイ?
061 * [ -binary=[false/true] ] ?trueは、バイナリファイルのコピ?(初期値:false)
062 * [ -changeCrLf=[false/true] ] ?trueは、バイナリファイルのコピ?時にCR+LFに変換しま?初期値:false)
063 * [ -keepTimeStamp=[false/true]] ?trueは、コピ???ファイルのタイ?タンプで作?しま?初期値:false)
064 * [ -display=[false/true] ] ?trueは、コピ?状況を表示しま?初期値:false)
065 * [ -debug=false|true ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
066 *
067 * @version 4.0
068 * @author Kazuhiko Hasegawa
069 * @since JDK5.0,
070 */
071 public class Process_FileCopy extends AbstractProcess implements ChainProcess {
072 private File tempFile = null;
073
074 private String inPath = null;
075 private String inEncode = null;
076 private String outPath = null;
077 private String outEncode = null;
078 private boolean binary = false;
079 private boolean changeCrLf = false; // 4.2.2.0 (2008/05/10)
080 private boolean keepTimeStamp = false; // 5.1.5.0 (2010/04/01)
081 private boolean display = false;
082 private boolean debug = false; // 5.7.3.0 (2014/02/07) ????
083
084 private int inPathLen = 0;
085 private boolean isEquals = false;
086 private int inCount = 0;
087
088 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map
089 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map
090
091 static {
092 mustProparty = new LinkedHashMap<String,String>();
093 mustProparty.put( "inPath", "コピ???ファイル基準パス" );
094
095 usableProparty = new LinkedHashMap<String,String>();
096 usableProparty.put( "inEncode", "コピ???ファイルのエンコードタイ? );
097 usableProparty.put( "outPath", "コピ?先?ファイル基準パス" );
098 usableProparty.put( "outEncode", "コピ?先?ファイルのエンコードタイ? );
099 usableProparty.put( "binary", "trueは、バイナリファイルをコピ?しま?初期値:false)" );
100 usableProparty.put( "changeCrLf", "trueは、バイナリファイルのコピ?時にCR+LFに変換しま?初期値:false)" ); // 4.2.2.0 (2008/05/10)
101 usableProparty.put( "keepTimeStamp", "trueは、コピ???ファイルのタイ?タンプで作?しま?初期値:false)" ); // 5.1.5.0 (2010/04/01)
102 usableProparty.put( "display", "trueは、コピ?状況を表示しま?初期値:false)" );
103 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? +
104 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ????
105 }
106
107 /**
108 * ?ォルトコンストラクター?
109 * こ?クラスは、動??されます??ォルトコンストラクターで?
110 * super クラスに対して、?な初期化を行っておきます?
111 *
112 */
113 public Process_FileCopy() {
114 super( "org.opengion.fukurou.process.Process_FileCopy",mustProparty,usableProparty );
115 }
116
117 /**
118 * プロセスの初期化を行います?初めに??、呼び出されます?
119 * 初期処?ファイルオープン??オープン?に使用します?
120 *
121 * @og.rev 4.2.2.0 (2008/05/10) changeCrLf 属?対?
122 * @og.rev 5.1.5.0 (2010/04/01) keepTimeStamp 属?の追?
123 *
124 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク?
125 */
126 public void init( final ParamProcess paramProcess ) {
127 Argument arg = getArgument();
128
129 inPath = arg.getProparty("inPath" );
130 outPath = arg.getProparty("outPath" );
131 inEncode = arg.getProparty("inEncode" ,System.getProperty("file.encoding"));
132 outEncode = arg.getProparty("outEncode",System.getProperty("file.encoding"));
133 binary = arg.getProparty("binary" ,binary);
134 changeCrLf = arg.getProparty("changeCrLf" ,changeCrLf); // 4.2.2.0 (2008/05/10)
135 keepTimeStamp = arg.getProparty("keepTimeStamp" ,keepTimeStamp); // 5.1.5.0 (2010/04/01)
136 display = arg.getProparty("display",display);
137 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ????
138 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ????
139
140 inPathLen = inPath.length();
141
142 // 入力と出力が同じか?
143 isEquals = outPath == null || inPath.equalsIgnoreCase( outPath );
144
145 if( binary ) {
146 // 4.2.2.0 (2008/05/10) 判定ミスの修正
147 if( ! inEncode.equalsIgnoreCase( outEncode ) ) {
148 String errMsg = "バイナリコピ?時には、?出力?エンコード?同じ?があります?" + CR
149 + " inEncode=[" + inEncode + "] , outEncode=[" + outEncode + "]" ;
150 throw new RuntimeException( errMsg );
151 }
152 if( isEquals ) {
153 String errMsg = "入出力が同じファイルのバイナリコピ?はできません? + CR
154 + " inPath=[" + inPath + "] , outPath=[" + outPath + "]" ;
155 throw new RuntimeException( errMsg );
156 }
157 }
158
159 // 入力と出力が同じ場合?、中間ファイルを作?します?
160 if( isEquals ) {
161 try {
162 tempFile = File.createTempFile( "X", ".tmp", new File( outPath ) );
163 tempFile.deleteOnExit();
164 }
165 catch( IOException ex ) {
166 String errMsg = "中間ファイル作?でエラーが発生しました? + CR
167 + " outPath=[" + outPath + "]" ;
168 throw new RuntimeException( errMsg,ex );
169 }
170 }
171 }
172
173 /**
174 * プロセスの終?行います??に??、呼び出されます?
175 * 終???ファイルクローズ??クローズ?に使用します?
176 *
177 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗]
178 */
179 public void end( final boolean isOK ) {
180 tempFile = null;
181 }
182
183 /**
184 * 引数の LineModel を??るメソ?です?
185 * 変換処?? LineModel を返します?
186 * 後続??行わな?????タのフィルタリングを行う場?は?
187 * null ??タを返します?つまり?null ??タは、後続??行わな?
188 * フラグの代わりにも使用して?す?
189 * なお?変換処?? LineModel と、オリジナルの LineModel が?
190 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す?
191 * ドキュメントに明記されて???合?、副作用が問題になる?合??
192 * ???とに自?コピ?(クローン)して下さ??
193 *
194 * @og.rev 4.0.0.0 (2007/11/28) メソ?の戻り?をチェ?します?
195 * @og.rev 4.2.2.0 (2008/05/10) changeCrLf 属?対?
196 * @og.rev 4.2.3.0 (2008/05/26) LineModel ?FileLineModel でな??合?処?
197 * @og.rev 5.1.5.0 (2010/04/01) keepTimeStamp 属?の追?
198 * @og.rev 5.1.6.0 (2010/05/01) changeCrLf 属?が?.FileUtil#changeCrLfcopy メソ?への移動に伴??
199 * @og.rev 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
200 *
201 * @param data オリジナルのLineModel
202 *
203 * @return 処?換後?LineModel
204 */
205 public LineModel action( final LineModel data ) {
206 inCount++ ;
207 final FileLineModel fileData ;
208 if( data instanceof FileLineModel ) {
209 fileData = (FileLineModel)data ;
210 }
211 else {
212 // LineModel ?FileLineModel でな??合?オブジェクトを作?します?
213 fileData = new FileLineModel( data );
214 // String errMsg = "??タ?FileLineModel オブジェクトではありません? + CR ;
215 // throw new RuntimeException( errMsg );
216 }
217
218 if( debug ) { println( "Before:" + data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
219
220 File inFile = fileData.getFile() ;
221 if( ! inFile.isFile() ) {
222 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
223 return data;
224 }
225
226 // ファイル名を作?します?
227 // ファイル名?、引数ファイル?から、inPath を引き、outPath を加えます?
228 File outFile = new File( outPath, inFile.getAbsolutePath().substring( inPathLen ) );
229 fileData.setFile( outFile );
230
231 // if( display ) { println( inFile + " => " + outFile ); }
232
233 // 入出力が異なる??
234 if( !isEquals ) {
235 tempFile = outFile;
236 File parent = outFile.getParentFile();
237 if( parent != null && ! parent.exists() && !parent.mkdirs() ) {
238 String errMsg = "??フォル?作?できませんでした?" + parent + "]" + CR
239 + " inCount=[" + inCount + "]件" + CR
240 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
241 throw new RuntimeException( errMsg );
242 }
243 }
244
245 if( binary ) {
246 // FileUtil.copy( inFile,tempFile );
247 // FileUtil.copy( inFile,tempFile,changeCrLf ); // 4.2.2.0 (2008/05/10)
248 // 5.1.6.0 (2010/05/01) changeCrLfcopy 対?
249 if( changeCrLf ) { FileUtil.changeCrLfcopy( inFile,tempFile ); }
250 else { FileUtil.copy( inFile,tempFile,keepTimeStamp ); }
251 }
252 else {
253 BufferedReader reader = FileUtil.getBufferedReader( inFile ,inEncode );
254 PrintWriter writer = FileUtil.getPrintWriter( tempFile ,outEncode );
255
256 try {
257 String line1;
258 while((line1 = reader.readLine()) != null) {
259 writer.println( line1 );
260 }
261 }
262 catch( IOException ex ) {
263 String errMsg = "ファイルコピ?中に例外が発生しました?" + data.getRowNo() + "]件目" + CR
264 + " inFile=[" + inFile + "] , tempFile=[" + tempFile + "]" + CR
265 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
266 throw new RuntimeException( errMsg,ex );
267 }
268 finally {
269 Closer.ioClose( reader ) ;
270 Closer.ioClose( writer ) ;
271 }
272 }
273
274 if( isEquals ) {
275 if( !outFile.delete() ) {
276 String errMsg = "??ファイルを削除できませんでした?" + outFile + "]" + CR
277 + " inCount=[" + inCount + "]件" + CR
278 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
279 throw new RuntimeException( errMsg );
280 }
281
282 if( !tempFile.renameTo( outFile ) ) {
283 String errMsg = "??ファイルをリネ??きませんでした?" + tempFile + "]" + CR
284 + " inCount=[" + inCount + "]件" + CR
285 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
286 throw new RuntimeException( errMsg );
287 }
288 }
289
290 // 5.1.5.0 (2010/04/01) keepTimeStamp 属?の追?
291 if( keepTimeStamp ) {
292 if( !outFile.setLastModified( inFile.lastModified() ) ) {
293 String errMsg = "lastModified 時間の設定が、できませんでした?" + outFile + "]" + CR
294 + " inCount=[" + inCount + "]件" + CR
295 + " data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
296 throw new RuntimeException( errMsg );
297 }
298 }
299
300 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
301 return data ;
302 }
303
304 /**
305 * プロセスの処?果のレポ?ト表現を返します?
306 * 処??ログラ?、?力件数、?力件数などの??です?
307 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ?
308 * 形式で出してください?
309 *
310 * @return 処?果のレポ??
311 */
312 public String report() {
313 String report = "[" + getClass().getName() + "]" + CR
314 + TAB + "Copy Count : " + inCount + CR
315 + TAB + "inPath : " + inPath + CR
316 + TAB + "inEncode : " + inEncode + CR
317 + TAB + "outPath : " + outPath + CR
318 + TAB + "outEncode : " + outEncode + CR
319 + TAB + "binary : " + binary ;
320
321 return report ;
322 }
323
324 /**
325 * こ?クラスの使用方法を返します?
326 *
327 * @return こ?クラスの使用方?
328 */
329 public String usage() {
330 StringBuilder buf = new StringBuilder();
331
332 buf.append( "Process_FileCopy は、上流から受け取っ?FileLineModelを??る?" ).append( CR );
333 buf.append( "ChainProcess インターフェースの実?ラスです?" ).append( CR );
334 buf.append( CR );
335 buf.append( "上流から受け取っ?FileLineModel の ファイルから、inPath の共通パス" ).append( CR );
336 buf.append( "以下?ファイルを?outPath の共通パス以下にコピ?します?" ).append( CR );
337 buf.append( "コピ?の種類?、バイナリか??ストで、テキスト?場合?、エンコー? ).append( CR );
338 buf.append( "変換も行うことが可能です?" ).append( CR );
339 buf.append( "inPath と outPath が同じ?また?、outPath が未設定?場合?、?力と出力が" ).append( CR );
340 buf.append( "同じです?で、???身のエンコード変換処?行うことになります?" ).append( CR );
341 buf.append( CR );
342 buf.append( "コピ?されるファイルのファイル名?、?力ファイル名と同?す?保存される" ).append( CR );
343 buf.append( "フォル?異なります?(同?することも可能です?)" ).append( CR );
344 buf.append( CR );
345 buf.append( "上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク? ).append( CR );
346 buf.append( "である、Process_FileSearch を使用するのが?便利です?それ以外?クラス? ).append( CR );
347 buf.append( "使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡? ).append( CR );
348 buf.append( "できれば、使用可能です?" ).append( CR );
349 buf.append( CR );
350 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR );
351 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR );
352 buf.append( "繋げてください? ).append( CR );
353 buf.append( CR ).append( CR );
354
355 buf.append( getArgument().usage() ).append( CR );
356
357 return buf.toString();
358 }
359
360 /**
361 * こ?クラスは、main メソ?から実行できません?
362 *
363 * @param args コマンド引数配?
364 */
365 public static void main( final String[] args ) {
366 LogWriter.log( new Process_FileCopy().usage() );
367 }
368 }