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