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         * 引数に &lt;file1&gt; &lt;file2&gt; [&lt;encode1&gt; &lt;encode2&gt;] を指定します。
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}