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