426

Java でファイルをコピーする唯一の方法は、ストリームを開き、バッファを宣言し、1 つのファイルを読み取り、それをループして、別のストリームに書き出すことであることにいつも悩まされてきました。Web には、このタイプのソリューションの同様の、しかしわずかに異なる実装が散らばっています。

Java言語の範囲内にとどまるより良い方法はありますか(つまり、OS固有のコマンドを実行する必要はありません)? おそらく、信頼できるオープン ソース ユーティリティ パッケージでは、少なくともこの基礎となる実装を覆い隠し、1 行のソリューションを提供するでしょうか?

4

16 に答える 16

279

Apache Commons のようなメガ API の使用は避けます。これは単純な操作であり、新しい NIO パッケージの JDK に組み込まれています。以前の回答ですでにリンクされていましたが、NIO API の主要なメソッドは新しい関数「transferTo」と「transferFrom」です。

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html#transferTo(long,%20long,%20java.nio.channels.WritableByteChannel)

リンクされた記事の 1 つは、transferFrom を使用して、この関数をコードに統合する優れた方法を示しています。

public static void copyFile(File sourceFile, File destFile) throws IOException {
    if(!destFile.exists()) {
        destFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;

    try {
        source = new FileInputStream(sourceFile).getChannel();
        destination = new FileOutputStream(destFile).getChannel();
        destination.transferFrom(source, 0, source.size());
    }
    finally {
        if(source != null) {
            source.close();
        }
        if(destination != null) {
            destination.close();
        }
    }
}

NIO の学習は少し難しい場合があるため、NIO を一晩学習する前に、このメカニズムを信頼することをお勧めします。個人的な経験から言えば、経験がなく、java.io ストリームを介して IO を紹介された場合、習得するのは非常に困難です。

于 2008-09-22T14:17:26.827 に答える
276

上記のツールキットで言及されているように、Apache Commons IO、具体的にはFileUtilsが最適です。copyFile() ; それはあなたのためにすべての重い持ち上げを処理します。

あとがきとして、FileUtils の最近のバージョン (2.0.1 リリースなど) では、ファイルのコピーに NIO の使用が追加されていることに注意してください。NIO は、ファイル コピーのパフォーマンスを大幅に向上させることができます。これは主に、NIO ルーチンが、Java レイヤーを介してバイトを読み書きすることによって処理するのではなく、OS/ファイル システムに直接コピーすることを延期するためです。そのため、パフォーマンスを求めている場合は、FileUtils の最新バージョンを使用していることを確認する価値があります。

于 2008-09-20T02:23:46.233 に答える
182

Java 7 では、次の try-with-resource 構文を使用できます。

public static void copyFile( File from, File to ) throws IOException {

    if ( !to.exists() ) { to.createNewFile(); }

    try (
        FileChannel in = new FileInputStream( from ).getChannel();
        FileChannel out = new FileOutputStream( to ).getChannel() ) {

        out.transferFrom( in, 0, in.size() );
    }
}

または、さらに良いことに、これは Java 7 で導入された新しい Files クラスを使用して実現することもできます。

public static void copyFile( File from, File to ) throws IOException {
    Files.copy( from.toPath(), to.toPath() );
}

かなりおしゃれですよね?

于 2011-07-28T18:22:35.277 に答える
92
  • これらのメソッドは、パフォーマンスが設計されています (オペレーティング システムのネイティブ I/O と統合されています)。
  • これらのメソッドは、ファイル、ディレクトリ、およびリンクで機能します。
  • 提供された各オプションは省略できます - これらはオプションです。

ユーティリティ クラス

package com.yourcompany.nio;

class Files {

    static int copyRecursive(Path source, Path target, boolean prompt, CopyOptions options...) {
        CopyVisitor copyVisitor = new CopyVisitor(source, target, options).copy();
        EnumSet<FileVisitOption> fileVisitOpts;
        if (Arrays.toList(options).contains(java.nio.file.LinkOption.NOFOLLOW_LINKS) {
            fileVisitOpts = EnumSet.noneOf(FileVisitOption.class) 
        } else {
            fileVisitOpts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        }
        Files.walkFileTree(source[i], fileVisitOpts, Integer.MAX_VALUE, copyVisitor);
    }

    private class CopyVisitor implements FileVisitor<Path>  {
        final Path source;
        final Path target;
        final CopyOptions[] options;

        CopyVisitor(Path source, Path target, CopyOptions options...) {
             this.source = source;  this.target = target;  this.options = options;
        };

        @Override
        FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
        // before visiting entries in a directory we copy the directory
        // (okay if directory already exists).
        Path newdir = target.resolve(source.relativize(dir));
        try {
            Files.copy(dir, newdir, options);
        } catch (FileAlreadyExistsException x) {
            // ignore
        } catch (IOException x) {
            System.err.format("Unable to create: %s: %s%n", newdir, x);
            return SKIP_SUBTREE;
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
        Path newfile= target.resolve(source.relativize(file));
        try {
            Files.copy(file, newfile, options);
        } catch (IOException x) {
            System.err.format("Unable to copy: %s: %s%n", source, x);
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
        // fix up modification time of directory when done
        if (exc == null && Arrays.toList(options).contains(COPY_ATTRIBUTES)) {
            Path newdir = target.resolve(source.relativize(dir));
            try {
                FileTime time = Files.getLastModifiedTime(dir);
                Files.setLastModifiedTime(newdir, time);
            } catch (IOException x) {
                System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x);
            }
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) {
        if (exc instanceof FileSystemLoopException) {
            System.err.println("cycle detected: " + file);
        } else {
            System.err.format("Unable to copy: %s: %s%n", file, exc);
        }
        return CONTINUE;
    }
}

ディレクトリまたはファイルのコピー

long bytes = java.nio.file.Files.copy( 
                 new java.io.File("<filepath1>").toPath(), 
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING,
                 java.nio.file.StandardCopyOption.COPY_ATTRIBUTES,
                 java.nio.file.LinkOption.NOFOLLOW_LINKS);

ディレクトリまたはファイルの移動

long bytes = java.nio.file.Files.move( 
                 new java.io.File("<filepath1>").toPath(), 
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.ATOMIC_MOVE,
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING);

ディレクトリまたはファイルを再帰的にコピーする

long bytes = com.yourcompany.nio.Files.copyRecursive( 
                 new java.io.File("<filepath1>").toPath(), 
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING,
                 java.nio.file.StandardCopyOption.COPY_ATTRIBUTES
                 java.nio.file.LinkOption.NOFOLLOW_LINKS );
于 2013-05-17T03:09:21.707 に答える
48

Java 7では簡単です...

File src = new File("original.txt");
File target = new File("copy.txt");

Files.copy(src.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
于 2014-06-20T18:38:26.580 に答える
24

これらのメカニズムはすべて、ファイルの内容のみをコピーし、権限などのメタデータはコピーしないことに注意してください。したがって、Linuxで実行可能.shファイルをコピーまたは移動した場合、新しいファイルは実行可能ではありません。

ファイルを真にコピーまたは移動するには、つまりコマンドラインからコピーした場合と同じ結果を得るには、実際にはネイティブツールを使用する必要があります。シェルスクリプトまたはJNIのいずれか。

どうやら、これはjava7で修正される可能性があります-http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html。成功を祈っている!

于 2008-09-23T03:38:29.490 に答える
23

Google の Guava ライブラリにもcopy メソッドがあります。

public static void copy ( File  from,
                         File  to)IOException
                 をスローします
あるファイルから別のファイルにすべてのバイトをコピーします。

警告:toが既存のファイルを表す場合、そのファイルは の内容で上書きされますfrom同じファイルtofrom参照すると、そのファイルの内容は削除されます。

パラメータ:from - ソース ファイルto- 宛先ファイル

例外: IOException - I/O エラーが発生した場合 IllegalArgumentException- iffrom.equals(to)

于 2010-07-05T16:17:19.010 に答える
18

Java 7 で標準として利用可能、path.copyTo: http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Path.html http://java.sun.com/docs/books/チュートリアル/エッセンシャル/io/copy.html

ファイルコピーのような一般的で単純なものを標準化するのに、彼らがこれほど長い時間を要したとは信じられません :(

于 2010-06-01T08:33:44.303 に答える
7

すでにSpringを使用しているWebアプリケーションを使用していて、単純なファイルコピーにApache Commons IOを含めたくない場合は、SpringフレームワークのFileCopyUtilsを使用できます。

于 2012-09-07T06:43:50.053 に答える
7

上記のコードで考えられる 3 つの問題:

  1. getChannel が例外をスローすると、開いているストリームがリークする可能性があります。
  2. 大きなファイルの場合、OS が処理できる以上の量を一度に転送しようとしている可能性があります。
  3. transferFrom の戻り値を無視しているため、ファイルの一部だけをコピーしている可能性があります。

org.apache.tools.ant.util.ResourceUtils.copyResourceこれが非常に複雑な理由です。また、transferFrom は問題ありませんが、Linux の JDK 1.4 では transferTo が壊れることにも注意してください ( Bug ID:5056395を参照) – Jesse Glick Jan

于 2012-04-13T09:36:31.757 に答える
6

1 行のコードで簡単にファイルをコピーできる 3 つの方法を次に示します。

Java7 :

java.nio.file.Files#copy

private static void copyFileUsingJava7Files(File source, File dest) throws IOException {
    Files.copy(source.toPath(), dest.toPath());
}

アパッチ コモンズ IO :

FileUtils#copyFile

private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
    FileUtils.copyFile(source, dest);
}

グァバ

ファイル#コピー

private static void copyFileUsingGuava(File source,File dest) throws IOException{
    Files.copy(source,dest);          
}
于 2014-11-13T11:57:18.453 に答える