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 }