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.util; 017 018import java.io.BufferedInputStream; 019import java.io.BufferedOutputStream; 020import java.io.BufferedReader; 021import java.io.BufferedWriter; 022import java.io.File; 023import java.io.InputStream; 024import java.io.FileInputStream; 025import java.io.FileNotFoundException; 026import java.io.FileOutputStream; 027import java.io.IOException; 028import java.io.InputStreamReader; 029import java.io.OutputStream; 030import java.io.OutputStreamWriter; 031import java.io.PrintWriter; 032import java.io.UnsupportedEncodingException; 033import java.io.Writer; 034import java.util.Collections; 035import java.util.List; 036 037import java.nio.channels.FileChannel; 038 039/** 040 * FileUtil.java は、共通的に使用される File関連メソッドを集約した、クラスです。 041 * 042 * 全変数は、public static final 宣言されており、全メソッドは、public static synchronized 宣言されています。 043 * 044 * @og.group ユーティリティ 045 * 046 * @version 4.0 047 * @author Kazuhiko Hasegawa 048 * @since JDK5.0, 049 */ 050public final class FileUtil { 051 private static final NonClosePrintWriter outWriter = new NonClosePrintWriter( System.out ); 052 private static final NonClosePrintWriter errWriter = new NonClosePrintWriter( System.err ); 053 054 /** システム依存の改行記号をセットします。 */ 055 private static final String CR = System.getProperty("line.separator"); 056 057 /** 5.6.1.2 (2013/02/22) UNIX系のファイル名を表すセパレータ文字 */ 058 private static final char UNIX_SEPARATOR = '/'; 059 060 /** 5.6.1.2 (2013/02/22) Windwos系のファイル名を表すセパレータ文字 */ 061 private static final char WINDOWS_SEPARATOR = '\\'; 062 063 /** 5.6.1.2 (2013/02/22) ファイルの拡張子の区切りを表す文字 */ 064 public static final char EXTENSION_SEPARATOR = '.'; 065 066 private static final byte B_CR = (byte)0x0d ; // '\r' 067 private static final byte B_LF = (byte)0x0a ; // '\n' 068 private static final int BUFSIZE = 8192 ; // 5.1.6.0 (2010/05/01) 069 070 /** 071 * すべてが staticメソッドなので、コンストラクタを呼び出さなくしておきます。 072 * 073 */ 074 private FileUtil() {} 075 076 /** 077 * Fileオブジェクトとエンコードより PrintWriterオブジェクトを作成します。 078 * 079 * @param file 出力するファイルオブジェクト 080 * @param encode ファイルのエンコード 081 * 082 * @return PrintWriterオブジェクト 083 * @throws RuntimeException 何らかのエラーが発生した場合 084 */ 085 public static PrintWriter getPrintWriter( final File file,final String encode ) { 086 return getPrintWriter( file,encode,false ); 087 } 088 089 /** 090 * Fileオブジェクトとエンコードより PrintWriterオブジェクトを作成します。 091 * 092 * @param file 出力するファイルオブジェクト 093 * @param encode ファイルのエンコード 094 * @param append ファイルを追加モード(true)にするかどうか 095 * 096 * @return PrintWriterオブジェクト 097 * @throws RuntimeException 何らかのエラーが発生した場合 098 */ 099 public static PrintWriter getPrintWriter( final File file,final String encode,final boolean append ) { 100 final PrintWriter writer ; 101 102 try { 103 writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter( 104 new FileOutputStream(file,append) ,encode ))); 105 } 106 catch( UnsupportedEncodingException ex ) { 107 String errMsg = "指定されたエンコーディングがサポートされていません。" + CR 108 + ex.getMessage() + CR 109 + "File=[" + file + " , encode=[" + encode + "]" ; 110 throw new RuntimeException( errMsg,ex ); 111 } 112 catch( FileNotFoundException ex ) { // 3.6.1.0 (2005/01/05) 113 String errMsg = "ファイル名がオープン出来ませんでした。" + CR 114 + ex.getMessage() + CR 115 + "File=[" + file + " , encode=[" + encode + "]" ; 116 throw new RuntimeException( errMsg,ex ); 117 } 118 119 return writer ; 120 } 121 122 /** 123 * ファイル名より、PrintWriterオブジェクトを作成する簡易メソッドです。 124 * 125 * これは、ファイル名は、フルパスで、追加モードで、UTF-8 エンコードの 126 * ログファイルを出力する場合に使用します。 127 * また、ファイル名に、"System.out" と、"System.err" を指定できます。 128 * その場合は、標準出力、または、標準エラー出力に出力されます。 129 * "System.out" と、"System.err" を指定した場合は、NonClosePrintWriter 130 * オブジェクトが返されます。これは、close() 処理が呼ばれても、何もしない 131 * クラスです。また、常に内部キャッシュの同じオブジェクトが返されます。 132 * 133 * @param file 出力するファイル名 134 * 135 * @return PrintWriterオブジェクト 136 * @throws RuntimeException 何らかのエラーが発生した場合 137 * @throws IllegalArgumentException ファイル名が null の場合 138 */ 139 public static PrintWriter getLogWriter( final String file ) { 140 if( file == null ) { 141 String errMsg = "ファイル名に、null は指定できません。"; 142 throw new IllegalArgumentException( errMsg ); 143 } 144 145 final PrintWriter writer ; 146 if( "System.out".equalsIgnoreCase( file ) ) { 147 writer = outWriter ; 148 } 149 else if( "System.err".equalsIgnoreCase( file ) ) { 150 writer = errWriter ; 151 } 152 else { 153 writer = getPrintWriter( new File( file ),"UTF-8",true ); 154 } 155 156 return writer ; 157 } 158 159 /** 160 * OutputStreamとエンコードより PrintWriterオブジェクトを作成します。 161 * 162 * @og.rev 5.5.2.0 (2012/05/01) 新規追加 163 * 164 * @param os 利用するOutputStream 165 * @param encode ファイルのエンコード 166 * 167 * @return PrintWriterオブジェクト 168 * @throws RuntimeException 何らかのエラーが発生した場合 169 */ 170 public static PrintWriter getPrintWriter( final OutputStream os,final String encode ) { 171 final PrintWriter writer ; 172 173 try { 174 writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter( 175 os ,encode ))); 176 } 177 catch( UnsupportedEncodingException ex ) { 178 String errMsg = "指定されたエンコーディングがサポートされていません。" + CR 179 + ex.getMessage() + CR 180 + "encode=[" + encode + "]" ; 181 throw new RuntimeException( errMsg,ex ); 182 } 183 return writer ; 184 } 185 186 /** 187 * PrintWriter を継承した、JspWriterなどの Writer 用のクラスを定義します。 188 * 189 * 例えば、JspWriterなどの JSP/Servlet等のフレームワークで使用される 190 * Writer では、flush や close 処理は、フレームワーク内で行われます。 191 * その場合、通常のファイルと同じ用に、flush や close をアプリケーション側で 192 * 行うと、内部処理的に不整合が発生したり、最悪の場合エラーになります。 193 * このクラスは、NonFlushPrintWriter クラスのオブジェクトを返します。 194 * これは、通常の、new PrintWriter( Writer ) で、求めるのと、ほとんど同様の 195 * 処理を行いますが、close() と flush() メソッドが呼ばれても、何もしません。 196 * 197 * @param writer 出力するWriteオブジェクト(NonFlushPrintWriterクラス) 198 * 199 * @return PrintWriterオブジェクト 200 */ 201 public static PrintWriter getNonFlushPrintWriter( final Writer writer ) { 202 return new NonFlushPrintWriter( writer ); 203 } 204 205 /** 206 * Fileオブジェクトとエンコードより BufferedReaderオブジェクトを作成します。 207 * 208 * @param file 入力するファイルオブジェクト 209 * @param encode ファイルのエンコード 210 * 211 * @return BufferedReaderオブジェクト 212 * @throws RuntimeException 何らかのエラーが発生した場合 213 */ 214 public static BufferedReader getBufferedReader( final File file,final String encode ) { 215 final BufferedReader reader ; 216 217 try { 218 reader = new BufferedReader(new InputStreamReader( 219 new FileInputStream( file ) ,encode )); 220 } 221 catch( UnsupportedEncodingException ex ) { 222 String errMsg = "指定されたエンコーディングがサポートされていません。" + CR 223 + ex.getMessage() + CR 224 + "FIle=[" + file + " , encode=[" + encode + "]" ; 225 throw new RuntimeException( errMsg,ex ); 226 } 227 catch( FileNotFoundException ex ) { 228 String errMsg = "ファイル名がオープン出来ませんでした。" + CR 229 + ex.getMessage() + CR 230 + "FIle=[" + file + " , encode=[" + encode + "]" ; 231 throw new RuntimeException( errMsg,ex ); 232 } 233 234 return reader ; 235 } 236 237 /** 238 * 指定のファイル名が、実際に存在しているかどうかをチェックします。 239 * 存在しない場合は、2秒毎に、3回確認します。 240 * それでも存在しない場合は、エラーを返します。 241 * return されるFileオブジェクトは、正規の形式(CanonicalFile)です。 242 * 243 * @param dir フォルダ名 244 * @param filename ファイル名 245 * 246 * @return 存在チェック(なければ null/あれば、CanonicalFile) 247 */ 248 public static File checkFile( final String dir, final String filename ) { 249 return checkFile( dir,filename,3 ); 250 } 251 252 /** 253 * 指定のファイル名が、実際に存在しているかどうかをチェックします。 254 * 存在しない場合は、2秒毎に、指定の回数分確認します。 255 * それでも存在しない場合は、エラーを返します。 256 * return されるFileオブジェクトは、正規の形式(CanonicalFile)です。 257 * 258 * @param dir フォルダ名 259 * @param filename ファイル名 260 * @param count 回数指定 261 * 262 * @return 存在チェック(なければ null/あれば、CanonicalFile) 263 */ 264 public static File checkFile( final String dir, final String filename,final int count ) { 265 File file = null; 266 267 int cnt = count; 268 while( cnt > 0 ) { 269 file = new File( dir,filename ); 270 if( file.exists() ) { break; } 271 else { 272 if( cnt == 1 ) { return null; } // 残り1回の場合は、2秒待機せずに即抜ける。 273 try { Thread.sleep( 2000 ); } // 2秒待機 274 catch ( InterruptedException ex ) { 275 System.out.println( "InterruptedException" ); 276 } 277 System.out.println(); 278 System.out.print( "CHECK File Error! CNT=" + cnt ); 279 System.out.print( " File=" + file.getAbsolutePath() ); 280 } 281 cnt--; 282 } 283 284 // ファイルの正式パス名の取得 285 try { 286 return file.getCanonicalFile() ; 287 } 288 catch( IOException ex ) { 289 String errMsg = "ファイルの正式パス名が取得できません。[" + file.getAbsolutePath() + "]"; 290 throw new RuntimeException( errMsg,ex ); 291 } 292 } 293 294 /** 295 * ファイルのバイナリコピーを行います。 296 * 297 * copy( File,File,false ) を呼び出します。 298 * 299 * @og.rev 5.1.6.0 (2010/05/01) 戻り値に、true/false 指定します。 300 * 301 * @param fromFile コピー元ファイル名 302 * @param toFile コピー先ファイル名 303 * 304 * @return バイナリコピーが正常に終了したかどうか[true:成功/false:失敗] 305 * @see #copy( File,File,boolean ) 306 */ 307 public static boolean copy( final String fromFile,final String toFile ) { 308 return copy( new File( fromFile ), new File( toFile ), false ); 309 } 310 311 /** 312 * ファイルのバイナリコピーを行います。 313 * 314 * copy( File,File,boolean ) を呼び出します。 315 * 第3引数の、keepTimeStamp=true で、コピー元のファイルのタイムスタンプを、 316 * コピー先にもセットします。 317 * 318 * @og.rev 5.1.6.0 (2010/05/01) 戻り値に、true/false 指定します。 319 * 320 * @param fromFile コピー元ファイル名 321 * @param toFile コピー先ファイル名 322 * @param keepTimeStamp タイムスタンプ維持[true/false] 323 * 324 * @return バイナリコピーが正常に終了したかどうか[true:成功/false:失敗] 325 * @see #copy( File,File,boolean ) 326 */ 327 public static boolean copy( final String fromFile,final String toFile,final boolean keepTimeStamp ) { 328 return copy( new File( fromFile ), new File( toFile ), keepTimeStamp ); 329 } 330 331 /** 332 * ファイルのバイナリコピーを行います。 333 * 334 * copy( File,File,false ) を呼び出します。 335 * 336 * @og.rev 5.1.6.0 (2010/05/01) 戻り値に、true/false 指定します。 337 * 338 * @param fromFile コピー元ファイル 339 * @param toFile コピー先ファイル 340 * 341 * @return バイナリコピーが正常に終了したかどうか[true:成功/false:失敗] 342 * @see #copy( File,File,boolean ) 343 */ 344 public static boolean copy( final File fromFile,final File toFile ) { 345 return copy( fromFile, toFile, false ); 346 } 347 348 /** 349 * ファイルのバイナリコピーを行います。 350 * 351 * 第3引数の、keepTimeStamp=true で、コピー元のファイルのタイムスタンプを、 352 * コピー先にもセットします。 353 * toFile が、ディレクトリの場合は、fromFile のファイル名をそのままコピーします。 354 * fromFile がディレクトリの場合は、エラーにします。 355 * copyDirectry( File,Fileboolean )を使用してください。(自動処理はしていません) 356 * 357 * @og.rev 5.1.6.0 (2010/05/01) 新規追加 358 * @og.rev 5.6.5.2 (2013/06/21) ByteBufferを利用した方式から、transferTo を使用する方式に変更 359 * @og.rev 5.7.1.2 (2013/12/20) copy先(toFile)のフォルダが存在しなければ、作成します。 360 * 361 * @param fromFile コピー元ファイル 362 * @param toFile コピー先ファイル 363 * @param keepTimeStamp タイムスタンプ維持[true/false] 364 * 365 * @return バイナリコピーが正常に終了したかどうか[true:成功/false:失敗] 366 * @see #copyDirectry( File,File,boolean ) 367 */ 368 public static boolean copy( final File fromFile,final File toFile,final boolean keepTimeStamp ) { 369 FileInputStream inFile = null; 370 FileOutputStream outFile = null; 371 FileChannel fin = null; 372 FileChannel fout = null; 373 374 File tempToFile = toFile ; 375 try { 376 // fromFileが、ディレクトリの場合は、エラー 377 if( fromFile.isDirectory() ) { 378 System.err.println( fromFile + " がディレクトリのため、処理できません。" ); 379 return false; 380 } 381 // toFileが、ディレクトリの場合は、そのパスでファイル名をfromFileから取り出す。 382 if( toFile.isDirectory() ) { 383 tempToFile = new File( toFile,fromFile.getName() ); 384 } 385 386 // 5.7.1.2 (2013/12/20) copy先(toFile)のフォルダが存在しなければ、作成します。 387 File parent = tempToFile.getParentFile(); 388 if( !parent.exists() && !parent.mkdirs() ) { 389 // ディレクトリを作成する 390 System.err.println( parent + " の ディレクトリ作成に失敗しました。" ); 391 return false; 392 } 393 394 inFile = new FileInputStream( fromFile ); 395 outFile = new FileOutputStream( tempToFile ); 396 397 fin = inFile.getChannel(); 398 fout = outFile.getChannel(); 399 400 // 5.6.5.2 (2013/06/21) ByteBufferを利用した方式から、transferTo を使用する方式に変更 401// ByteBuffer buffer = ByteBuffer.allocateDirect( BUFSIZE ); 402// while ( (fin.read(buffer) != -1) || buffer.position() > 0) { 403// buffer.flip(); 404// fout.write( buffer ); 405// buffer.compact(); 406// } 407 408 fin.transferTo(0, fin.size(), fout ); 409 410 } 411 catch ( IOException ex ) { 412 System.out.println(ex.getMessage()); 413 return false; 414 } 415 finally { 416 Closer.ioClose( inFile ) ; 417 Closer.ioClose( outFile ); 418 Closer.ioClose( fin ) ; 419 Closer.ioClose( fout ); 420 } 421 422 if( keepTimeStamp ) { 423 return tempToFile.setLastModified( fromFile.lastModified() ); 424 } 425 426 return true; 427 } 428 429 /** 430 * ファイルのバイナリコピーを行います。 431 * 432 * このファイルコピーは、バイナリファイルの 改行コードを 433 * CR+LF に統一します。また、UTF-8 の BOM(0xef,0xbb,0xbf) があれば、 434 * 取り除きます。 435 * 436 * @og.rev 5.1.6.0 (2010/05/01) 新規追加 437 * 438 * @param fromFile コピー元ファイル 439 * @param toFile コピー先ファイル 440 * 441 * @return バイナリコピーが正常に終了したかどうか[true:成功/false:失敗] 442 */ 443 public static boolean changeCrLfcopy( final File fromFile,final File toFile ) { 444 BufferedInputStream fromStream = null; 445 BufferedOutputStream toStream = null; 446 File tempToFile = toFile ; 447 try { 448 // ディレクトリの場合は、そのパスでファイル名をfromFileから取り出す。 449 if( toFile.isDirectory() ) { 450 tempToFile = new File( toFile,fromFile.getName() ); 451 } 452 fromStream = new BufferedInputStream( new FileInputStream( fromFile ) ); 453 toStream = new BufferedOutputStream( new FileOutputStream( tempToFile ) ); 454 455 byte[] buf = new byte[BUFSIZE]; 456 int len ; 457 // 4.2.3.0 (2008/05/26) changeCrLf 属性対応 458 459 boolean bomCheck = true; // 最初の一回だけ、BOMチェックを行う。 460 byte bt = (byte)0x00; // バッファの最後と最初の比較時に使用 461 while( (len = fromStream.read(buf,0,BUFSIZE)) != -1 ) { 462 int st = 0; 463 if( bomCheck && len >= 3 && 464 buf[0] == (byte)0xef && 465 buf[1] == (byte)0xbb && 466 buf[2] == (byte)0xbf ) { 467 st = 3; 468 } 469 else { 470 // バッファの最後が CR で、先頭が LF の場合、LF をパスします。 471 if( bt == B_CR && buf[0] == B_LF ) { 472 st = 1 ; 473 } 474 } 475 bomCheck = false; 476 477 for( int i=st;i<len;i++ ) { 478 bt = buf[i] ; 479 if( bt == B_CR || bt == B_LF ) { 480 toStream.write( (int)B_CR ); // CR 481 toStream.write( (int)B_LF ); // LF 482 // CR+LF の場合 483 if( bt == B_CR && i+1 < len && buf[i+1] == B_LF ) { 484 i++; 485 bt = buf[i] ; 486 } 487 } 488 else { 489 toStream.write( (int)bt ); 490 } 491 } 492 } 493 // 最後が改行コードでなければ、改行コードを追加します。 494 // テキストコピーとの互換性のため 495 if( bt != B_CR && bt != B_LF ) { 496 toStream.write( (int)B_CR ); // CR 497 toStream.write( (int)B_LF ); // LF 498 } 499 } 500 catch ( IOException ex ) { 501 System.out.println(ex.getMessage()); 502 return false; 503 } 504 finally { 505 Closer.ioClose( fromStream ) ; 506 Closer.ioClose( toStream ) ; 507 } 508 509 return true; 510 } 511 512 /** 513 * 入出力ストリーム間でデータの転送を行います。 514 * 515 * ここでは、すでに作成されたストリームに基づき、データの入出力を行います。 516 * よって、先にフォルダ作成や、存在チェック、ファイルの削除などの必要な処理は 517 * 済まして置いてください。 518 * また、このメソッド内で、ストリームのクロース処理は行っていません。 519 * 520 * @og.rev 5.1.6.0 (2010/05/01) 新規追加 521 * 522 * @param input 入力ストリーム 523 * @param output 出力ストリーム 524 * 525 * @return データ転送が正常に終了したかどうか[true:成功/false:失敗] 526 */ 527 public static boolean copy( final InputStream input,final OutputStream output ) { 528 if( input == null ) { 529 System.err.println( "入力ストリームが 作成されていません。" ); 530 return false; 531 } 532 533 if( output == null ) { 534 System.err.println( "出力ストリームが 作成されていません。" ); 535 return false; 536 } 537 538 try { 539 byte[] buf = new byte[BUFSIZE]; 540 int len; 541 while((len = input.read(buf)) != -1) { 542 output.write(buf, 0, len); 543 } 544 } 545 catch ( IOException ex ) { 546 System.out.println( ex.getMessage() ); 547 return false; 548 } 549 // finally { 550 // Closer.ioClose( input ); 551 // Closer.ioClose( output ); 552 // } 553 return true ; 554 } 555 556 /** 557 * 再帰処理でディレクトリのコピーを行います。 558 * 559 * 指定されたコピー元ディレクトリがディレクトリでなかったり存在しないときは falseを返します。 560 * 561 * @og.rev 4.3.0.0 (2008/07/24) 追加 562 * @og.rev 5.1.6.0 (2010/05/01) 戻り値に、true/false 指定します。 563 * 564 * @param fromDir コピー元ディレクトリ名 565 * @param toDir コピー先ディレクトリ名 566 * 567 * @return ディレクトリのコピーが正常に終了したかどうか[true:成功/false:失敗] 568 */ 569 public static boolean copyDirectry( final String fromDir, final String toDir ) { 570 return copyDirectry( new File( fromDir ), new File( toDir ),false ); 571 } 572 573 /** 574 * 再帰処理でディレクトリをコピーします。 575 * 576 * 指定されたコピー元ディレクトリがディレクトリでなかったり存在しないときは falseを返します。 577 * 578 * @og.rev 4.3.0.0 (2008/07/24) 追加 579 * @og.rev 5.1.6.0 (2010/05/01) 内部処理を若干変更します。 580 * 581 * @param fromDir コピー元ディレクトリ 582 * @param toDir コピー先ディレクトリ 583 * 584 * @return ディレクトリのコピーが正常に終了したかどうか[true:成功/false:失敗] 585 */ 586 public static boolean copyDirectry( final File fromDir, final File toDir ) { 587 return copyDirectry( fromDir, toDir, false ); 588 } 589 590 /** 591 * 再帰処理でディレクトリをコピーします。 592 * 593 * 指定されたコピー元ディレクトリがディレクトリでなかったり存在しないときは falseを返します。 594 * 595 * @og.rev 4.3.0.0 (2008/07/24) 追加 596 * @og.rev 5.1.6.0 (2010/05/01) 内部処理を若干変更します。 597 * @og.rev 5.3.7.0 (2011/07/01) フォルダにアクセスできない場合は、エラーを返します。 598 * 599 * @param fromDir コピー元ディレクトリ 600 * @param toDir コピー先ディレクトリ 601 * @param keepTimeStamp タイムスタンプ維持[true/false] 602 * 603 * @return ディレクトリのコピーが正常に終了したかどうか[true:成功/false:失敗] 604 */ 605 public static boolean copyDirectry( final File fromDir, final File toDir, final boolean keepTimeStamp ) { 606 // コピー元がディレクトリでない場合はfalseを返す 607 // 4.3.4.4 (2009/01/01) 608 if( !fromDir.exists() || !fromDir.isDirectory() ) { 609 System.err.println( fromDir + " が ディレクトリでないか、存在しません。" ); 610 return false; 611 } 612 613 // 4.3.4.4 (2009/01/01) ディレクトリを作成する 614 // 6.0.0.1 (2014/04/25) These nested if statements could be combined 615 if( !toDir.exists() && !toDir.mkdirs() ) { 616 System.err.println( toDir + " の ディレクトリ作成に失敗しました。" ); 617 return false; 618 } 619 620 // ディレクトリ内のファイルをすべて取得する 621 File[] files = fromDir.listFiles(); 622 623 // 5.3.7.0 (2011/07/01) フォルダにアクセスできない場合は、エラー 624 if( files == null ) { 625 System.err.println( fromDir + " はアクセスできません。" ); 626 return false; 627 } 628 629 // ディレクトリ内のファイルに対しコピー処理を行う 630 boolean flag = true; 631 for( int i = 0; files.length>i; i++ ){ 632 if( files[i].isDirectory() ){ // ディレクトリだった場合は再帰呼び出しを行う 633 flag = copyDirectry( files[i], new File( toDir, files[i].getName()),keepTimeStamp ); 634 } 635 else{ // ファイルだった場合はファイルコピー処理を行う 636 flag = copy( files[i], new File( toDir, files[i].getName()),keepTimeStamp ); 637 } 638 if( !flag ) { return false; } 639 } 640 return true; 641 } 642 643 /** 644 * 指定されたファイル及びディレクトを削除します。 645 * ディレクトリの場合はサブフォルダ及びファイルも削除します。 646 * 1つでもファイルの削除に失敗した場合、その時点で処理を中断しfalseを返します。 647 * 648 * @og.rev 5.3.7.0 (2011/07/01) フォルダにアクセスできない場合は、エラーを返します。 649 * 650 * @param file 削除ファイル/ディレクトリ 651 * 652 * @return ファイル/ディレクトリの削除に終了したかどうか[true:成功/false:失敗] 653 */ 654 public static boolean deleteFiles( final File file ) { 655 if( file.exists() ) { 656 if( file.isDirectory() ) { 657 File[] list = file.listFiles(); 658 659 // 5.3.7.0 (2011/07/01) フォルダにアクセスできない場合は、エラー 660 if( list == null ) { 661 System.err.println( file + " はアクセスできません。" ); 662 return false; 663 } 664 665 for( int i=0; i<list.length; i++ ) { 666 deleteFiles( list[i] ); 667 } 668 } 669 if( !file.delete() ) { return false; } 670 } 671 return true; 672 } 673 674 /** 675 * 指定されたディレクトリを基点としたファイル名(パスを含む)の一覧を返します。 676 * 677 * @og.rev 4.3.6.6 (2009/05/15) 新規作成 678 * @og.rev 5.4.3.2 (2012/01/06) 引数isCopy追加 679 * 680 * @param dir 基点となるディレクトリ 681 * @param sort ファイル名でソートするか 682 * @param list ファイル名一覧を格納するList 683 * @param isCopy コピー中ファイルを除外するか [true:含む/false:除外] 684 */ 685 public static void getFileList( final File dir, final boolean sort, final List<String> list, boolean isCopy ) { 686 if( list == null ) { return; } 687 if( dir.isFile() ) { 688 // コピー中判定はrenameで行う 689 if( !isCopy && !dir.renameTo( dir ) ){ 690 return; 691 } 692 else{ 693 list.add( dir.getAbsolutePath() ); 694 } 695 } 696 else if( dir.isDirectory() ) { 697 File[] files = dir.listFiles(); 698 for( int i=0; i<files.length; i++ ) { 699 getFileList( files[i], sort, list, isCopy ); 700 } 701 } 702 if( sort ) { 703 Collections.sort( list ); 704 } 705 } 706 707 /** 708 * 指定されたディレクトリを基点としたファイル名(パスを含む)の一覧を返します。 709 * 互換性のため、コピー中ファイルも含みます。 710 * 711 * @og.rev 5.4.3.2 (2012/01/06) コピー中対応のため引数4つを作成する 712 * 713 * @param dir 基点となるディレクトリ 714 * @param sort ファイル名でソートするか 715 * @param list ファイル名一覧を格納するList 716 */ 717 public static void getFileList( final File dir, final boolean sort, final List<String> list ) { 718 getFileList( dir, sort, list, true ); 719 } 720 721 /** 722 * 指定されたファイル名(パスを含む)から、パスも拡張子もないファイル名を返します。 723 * 724 * @og.rev 5.6.1.2 (2013/02/22) 新規作成 725 * 726 * @param filename ファイル名(パスを含む) 727 * @return パスも、拡張子もないファイル名 728 */ 729 public static String getBaseName( final String filename ) { 730 731 if (filename == null) { 732 return null; 733 } 734 735 // セパレータの位置を取得。 736 int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR); 737 int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR); 738 int lastSepPos = Math.max( lastUnixPos , lastWindowsPos ); 739 740 // 拡張子の位置を取得。 741 int extPos = filename.lastIndexOf(EXTENSION_SEPARATOR); 742 if( lastSepPos > extPos ) { extPos = -1; } // 念のため、最後のセパレータより前にある拡張子の区切り文字は無効。 743 744 if( extPos < 0 ) { 745 // SEPARATOR がなければ、lastSepPos + 1 = 0 となり、先頭から取得できる。 746 return filename.substring( lastSepPos + 1 ); 747 } else { 748 return filename.substring( lastSepPos + 1 , extPos ); 749 } 750 } 751 752 /** 753 * ファイルをリネームを行います。 754 * 引数のuseBackup属性を true にすると、toFile が存在した場合、toFile の直下に "_backup" フォルダを 755 * 作成して、toFile + "_" + (現在時刻のLONG値) + "." + (toFileの拡張子) に名前変更します。 756 * useBackup属性を false にすると、toFile が存在した場合、toFile を削除します。 757 * 758 * @og.rev 5.7.1.2 (2013/12/20) 新規追加 759 * 760 * @param fromFile 名前変更する元のファイル 761 * @param toFile 名前変更後のファイル 762 * @param useBackup バックアップを作成するかどうか(true:作成する/false:作成しない) 763 * @return true:正常処理/false:異常処理 764 */ 765 public static boolean renameTo( final File fromFile , final File toFile , final boolean useBackup ) { 766 if( fromFile == null || toFile == null ) { 767 String errMsg = "入力ファイルが null です。" ; 768 System.err.println( errMsg ); 769 return false; 770 } 771 772 // 変更先のファイルが存在した場合の処理。 773 if( toFile.exists() ) { 774 // バックアップ作成する場合 775 if( useBackup ) { 776 File parent = toFile.getParentFile(); // バックアップすべきファイルのフォルダ 777 File backup = new File( parent , "_backup" ); // その直下に、"_backup" フォルダを作成 778 if( !backup.exists() && !backup.mkdirs() ) { 779 String errMsg = "バックアップ処理でbackupフォルダの作成に失敗しました。[" + backup + "]"; 780 System.err.println( errMsg ); 781 return false; 782 } 783 // バックアップファイル名は、元のファイル名(拡張子含む) + "_" + 現在時刻のlong値 + "." + 元のファイルの拡張子 784 String bkupName = toFile.getName(); 785 File toFile2 = new File( parent,bkupName ); // オリジナルの toFile をrename するとまずいので、同名のFileオブジェクトを作成 786 787 bkupName = bkupName + "_" + System.currentTimeMillis() + "." + getExtension( bkupName ) ; 788 File bkupFile = new File( backup,bkupName ); 789 790 if( !toFile2.renameTo( bkupFile ) ) { 791 String errMsg = "バックアップ処理でバックアップファイルをリネームできませんでした。" +CR 792 + " [" + toFile + "] ⇒ [" + bkupFile + "]" ; 793 System.err.println( errMsg ); 794 return false; 795 } 796 } 797 // バックアップ作成しない場合は、削除します。 798 else if( !toFile.delete() ) { 799 String errMsg = "既存のファイル[" + toFile + "]が削除できませんでした。"; 800 System.err.println( errMsg ); 801 return false; 802 } 803 } 804 805 if( !fromFile.renameTo( toFile ) ) { 806 String errMsg = "所定のファイルをリネームできませんでした。" + CR 807 + " [" + fromFile + "] ⇒ [" + toFile + "]" ; 808 System.err.println( errMsg ); 809 return false; 810 } 811 return true; 812 } 813 814 /** 815 * ファイル名から 拡張子を取得します。 816 * 817 * 一番最後に見つかったピリオドから後ろを切り取って返します。 818 * 拡張子の区切り文字(".")がなければ、空文字列を返します。 819 * 820 * @og.rev 5.7.1.2 (2013/12/20) UploadedFileからに移動。若干のロジック変更 821 * 822 * @param fileName ファイル名 823 * @return 拡張子 824 */ 825 public static String getExtension( final String fileName ) { 826 int extPos = fileName.lastIndexOf( EXTENSION_SEPARATOR ); 827 if( extPos >= 0 ) { 828 return fileName.substring( extPos + 1 ); 829 } 830 return ""; 831 } 832 833 /** 834 * PrintWriter を継承した、System.out/System.err 用のクラスを定義します。 835 * 836 * 通常の、new PrintWriter( OutputStream ) で、求めるのと、ほとんど同様の 837 * 処理を行います。 838 * ただ、close() メソッドが呼ばれても、何もしません。 839 * 840 */ 841 private static final class NonClosePrintWriter extends PrintWriter { 842 /** 843 * コンストラクター 844 * 845 * new PrintWriter( OutputStream ) を行います。 846 * 847 * @param out OutputStream 848 */ 849 public NonClosePrintWriter( final OutputStream out ) { 850 super( out ); 851 } 852 853 /** 854 * close() メソッドをオーバーライドします。 855 * 856 * 何もしません。 857 * 858 */ 859 public void close() { 860 // ここでは処理を行いません。 861 } 862 } 863 864 /** 865 * PrintWriter を継承した、JspWriterなどの Writer 用のクラスを定義します。 866 * 867 * 例えば、JspWriterなどの JSP/Servlet等のフレームワークで使用される 868 * Writer では、flush や close 処理は、フレームワーク内で行われます。 869 * その場合、通常のファイルと同じ用に、flush や close をアプリケーション側で 870 * 行うと、内部処理的に不整合が発生したり、最悪の場合エラーになります。 871 * このクラスは、単に、通常の、new PrintWriter( Writer ) で、求めるのと、 872 * ほとんど同様の処理を行います。 873 * ただ、close() と flush() メソッドが呼ばれても、何もしません。 874 * 875 */ 876 private static final class NonFlushPrintWriter extends PrintWriter { 877 /** 878 * コンストラクター 879 * 880 * new PrintWriter( Writer ) を行います。 881 * 882 * @param writer Writer 883 */ 884 public NonFlushPrintWriter( final Writer writer ) { 885 super( writer ); 886 } 887 888 /** 889 * close() メソッドをオーバーライドします。 890 * 891 * 何もしません。 892 * 893 */ 894 public void close() { 895 // ここでは処理を行いません。 896 } 897 898 /** 899 * flush() メソッドをオーバーライドします。 900 * 901 * 何もしません。 902 * 903 */ 904 public void flush() { 905 // ここでは処理を行いません。 906 } 907 } 908 909 /** 910 * ファイルをコピーします。 911 * 912 * 引数に <file1> <file2> [<encode1> <encode2>] を指定します。 913 * file1 を読み込み、file2 にコピーします。コピー前に、file2 は、file2_backup にコピーします。 914 * file1 が、ディレクトリの場合は、ディレクトリごとコピーします。 915 * encode1、encode2 を指定すると、エンコード変換しながらコピーになります。 916 * この場合は、ファイル同士のコピーのみになります。 917 * 918 * @og.rev 4.0.0.0 (2007/11/28) メソッドの戻り値をチェックします。 919 * @og.rev 5.1.6.0 (2010/05/01) 引数の並び順、処理を変更します。 920 * 921 * @param args 引数配列 file1 file2 [encode1 encode2] 922 * @throws Throwable なんらかのエラーが発生した場合。 923 */ 924 public static void main( final String[] args ) throws Throwable { 925 if( args.length != 2 && args.length != 4 ) { 926 LogWriter.log("Usage: java org.opengion.fukurou.util.FileUtil <file1> <file2> [<encode1> <encode2>]" ); 927 return ; 928 } 929 930 File file1 = new File( args[0] ); 931 File file2 = new File( args[1] ); 932 933 File tempFile = new File( args[1] + "_backup" ); 934 935 if( args.length < 3 ) { 936 if( file1.isDirectory() ) { 937 FileUtil.copyDirectry( file1, file2, true ); 938 } 939 else { 940 FileUtil.copy( file2,tempFile ); 941 FileUtil.copy( file1,file2, true ); 942 } 943 } 944 else { 945 String encode1 = args[2]; 946 String encode2 = args[3]; 947 948 FileUtil.copy( file2,tempFile ); 949 950 BufferedReader reader = FileUtil.getBufferedReader( file1 ,encode1 ); 951 PrintWriter writer = FileUtil.getPrintWriter( file2 ,encode2 ); 952 953 try { 954 String line1; 955 while((line1 = reader.readLine()) != null) { 956 writer.println( line1 ); 957 } 958 } 959 finally { 960 Closer.ioClose( reader ) ; 961 Closer.ioClose( writer ) ; 962 } 963 } 964 } 965}