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