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