Méthode concise Standard pour copier un fichier en Java?

cela m'a toujours gêné que la seule façon de copier un fichier en Java implique d'ouvrir des flux, de déclarer un tampon, de lire dans un fichier, de le parcourir en boucle et de l'écrire à l'autre steam. Le web est jonché d'implémentations similaires, mais légèrement différentes de ce type de solution.

y a-t-il une meilleure façon de rester dans les limites du langage Java (qui n'implique pas l'exécution de commandes spécifiques à OS)? Peut-être dans certaines fiable le paquet d'utilitaire open source, qui au moins obscurcirait cette implémentation sous-jacente et fournirait une solution d'une ligne?

407
demandé sur Peter 2008-09-20 05:59:09

16 réponses

comme toolkit l'indique ci-dessus, Apache Commons IO est la voie à suivre, en particulier FileUtils . copyFile () ; il s'occupe de tout le levage lourd pour vous.

et comme postscript, notez que les versions récentes de FileUtils (comme la version 2.0.1) ont ajouté L'utilisation de NIO pour copier des fichiers; NIO peut augmenter de manière significative la performance de copie de fichiers , en grande partie parce que les routines de NIO défèrent copier directement dans le système D'exploitation / le système de fichiers plutôt que de le gérer en lisant et en écrivant des octets à travers la couche Java. Donc, si vous êtes à la recherche de performances, il pourrait être intéressant de vérifier que vous utilisez une version récente de FileUtils.

268
répondu delfuego 2016-06-28 01:43:34

j'éviterais l'utilisation d'une api mega comme apache commons. Il s'agit d'une opération simpliste et elle est intégrée dans le JDK dans le nouveau paquet NIO. Il était en quelque sorte déjà lié à dans une réponse précédente, mais la méthode clé dans L'api NIO sont les nouvelles fonctions "transferTo" et "transfer from".

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

un des articles liés montre une grande façon sur la façon d'intégrer cette fonction dans votre code, en utilisant le transfert de:

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();
        }
    }
}

apprendre NIO peut être un peu délicat, donc vous pourriez vouloir faire confiance à ce mécanicien avant de partir et d'essayer d'apprendre NIO du jour au lendemain. Par expérience personnelle, il peut être une chose très difficile à apprendre si vous n'avez pas l'expérience et ont été introduites à IO via le java.io ruisseaux.

273
répondu Josh 2011-08-15 13:15:06

maintenant avec Java 7, vous pouvez utiliser la syntaxe suivante 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() );
    }
}

ou, mieux encore, cela peut aussi être accompli en utilisant la nouvelle classe de fichiers introduite en Java 7:

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

plutôt snazzy, hein?

178
répondu Scott 2011-07-29 23:01:52
  • ces méthodes sont conçues en fonction des performances (elles s'intègrent aux e/s natives du système d'exploitation).
  • ces méthodes fonctionnent avec des fichiers, des répertoires et des liens.
  • chacune des options fournies peut être omise - elles sont facultatives.

la classe d'utilité

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;
    }
}

copier un répertoire ou un fichier

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);

le Déplacement d'un répertoire ou d'un fichier

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);

copier récursivement un répertoire ou un fichier

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 );
82
répondu Glen Best 2016-01-20 17:30:30

en Java 7, c'est facile...

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

Files.copy(src.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
34
répondu Kevin Sadler 2014-06-21 08:20:48

Pour copier un fichier et l'enregistrer sur votre chemin de destination, vous pouvez utiliser la méthode ci-dessous.

public void copy(File src, File dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}
26
répondu Rakshi 2015-09-28 20:54:48

notez que tous ces mécanismes ne copient que le contenu du fichier, et non les métadonnées telles que les permissions. Donc si vous deviez copier ou déplacer un exécutable .le nouveau fichier ne serait pas exécutable.

pour vraiment copier ou déplacer un fichier, c'est-à-dire pour obtenir le même résultat que Copier depuis une ligne de commande, vous devez en fait utiliser un outil natif. Soit un script shell, soit JNI.

apparemment, cela pourrait être corrigé en java 7 - http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html . Je croise les doigts!

24
répondu brad 2008-09-23 03:38:29

bibliothèque de goyave de Google a également un méthode de copie :

public static void copy(File from,
                        File to)
                 throws IOException
Copie tous les octets d'un fichier à l'autre.

attention: si to représente un fichier existant, ce fichier sera remplacé par le contenu de from . Si to et from reportez-vous à la même du fichier, le contenu de ce fichier seront supprimés.

paramètres: from - le fichier source to - le fichier de destination

lancers: IOException - en cas d'erreur d'E/S IllegalArgumentException - si from.equals(to)

21
répondu Andrew McKinlay 2017-02-26 20:05:28

disponible en standard en Java 7, path.copyTo: http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Path.html http://java.sun.com/docs/books/tutorial/essential/io/copy.html

Je ne peux pas croire qu'ils ont mis autant de temps à standardiser quelque chose d'aussi commun et simple que la copie de fichiers: (

19
répondu Ryan 2010-06-01 08:33:44

trois problèmes possibles avec le code ci-dessus:

  1. si getChannel fait une exception, vous pourriez faire fuiter un cours d'eau ouvert.
  2. pour les gros fichiers, vous pourriez essayer de transférer plus d'une fois que L'OS peut gérer.
  3. vous ignorez la valeur de retour de transfer from, Il se peut donc qu'elle ne copie qu'une partie du fichier.

C'est pourquoi org.apache.tools.ant.util.ResourceUtils.copyResource est si compliqué. Également notez que si transfer from est OK, transferTo breaks sur JDK 1.4 sous Linux (voir Bug ID: 5056395 ) - Jesse Glick Jan

7
répondu saji 2012-04-17 21:18:46

si vous êtes dans une application web qui utilise déjà Spring et si vous ne voulez pas inclure Apache Commons IO pour une simple copie de fichier, vous pouvez utiliser FileCopyUtils du framework Spring.

7
répondu Balaji Paulrajan 2012-09-07 06:43:50

Voici trois façons que vous pouvez facilement copier des fichiers avec une seule ligne de code!

Java7 :

de java.nio.fichier.Dossiers # copie

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

Appache Commons IO :

FileUtils#copyFile

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

Goyave :

"1519260920 de Fichiers"#copie

private static void copyFileUsingGuava(File source,File dest) throws IOException{
    Files.copy(source,dest);          
}
6
répondu Jaskey 2014-11-13 11:57:18
public static void copyFile(File src, File dst) throws IOException
{
    long p = 0, dp, size;
    FileChannel in = null, out = null;

    try
    {
        if (!dst.exists()) dst.createNewFile();

        in = new FileInputStream(src).getChannel();
        out = new FileOutputStream(dst).getChannel();
        size = in.size();

        while ((dp = out.transferFrom(in, p, size)) > 0)
        {
            p += dp;
        }
    }
    finally {
        try
        {
            if (out != null) out.close();
        }
        finally {
            if (in != null) in.close();
        }
    }
}
5
répondu user3200607 2014-01-16 01:25:45

rapide et travailler avec toutes les versions de Java aussi Android:

private void copy(final File f1, final File f2) throws IOException {
    f2.createNewFile();

    final RandomAccessFile file1 = new RandomAccessFile(f1, "r");
    final RandomAccessFile file2 = new RandomAccessFile(f2, "rw");

    file2.getChannel().write(file1.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, f1.length()));

    file1.close();
    file2.close();
}
2
répondu user1079877 2013-11-14 09:43:21

copie NIO avec tampon est la plus rapide selon mon test. Voir le code de travail ci-dessous d'un projet d'essai de mine à https://github.com/mhisoft/fastcopy

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;


public class test {

private static final int BUFFER = 4096*16;
static final DecimalFormat df = new DecimalFormat("#,###.##");
public static void nioBufferCopy(final File source, final File target )  {
    FileChannel in = null;
    FileChannel out = null;
    double  size=0;
    long overallT1 =  System.currentTimeMillis();

    try {
        in = new FileInputStream(source).getChannel();
        out = new FileOutputStream(target).getChannel();
        size = in.size();
        double size2InKB = size / 1024 ;
        ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER);

        while (in.read(buffer) != -1) {
            buffer.flip();

            while(buffer.hasRemaining()){
                out.write(buffer);
            }

            buffer.clear();
        }
        long overallT2 =  System.currentTimeMillis();
        System.out.println(String.format("Copied %s KB in %s millisecs", df.format(size2InKB),  (overallT2 - overallT1)));
    }
    catch (IOException e) {
        e.printStackTrace();
    }

    finally {
        close(in);
        close(out);
    }
}

private static void close(Closeable closable)  {
    if (closable != null) {
        try {
            closable.close();
        } catch (IOException e) {
            if (FastCopy.debug)
                e.printStackTrace();
        }    
    }
}

}

2
répondu Tony 2015-02-07 22:57:44

un peu en retard pour la partie, Mais voici une comparaison du temps pris pour copier un fichier en utilisant diverses méthodes de copie de fichier. J'ai suivi les méthodes 10 fois et j'ai pris une moyenne. Le transfert de fichiers par IO streams semble être le pire candidat:

Comparison of file transfer using various methods

Voici les méthodes:

private static long fileCopyUsingFileStreams(File fileToCopy, File newFile) throws IOException {
    FileInputStream input = new FileInputStream(fileToCopy);
    FileOutputStream output = new FileOutputStream(newFile);
    byte[] buf = new byte[1024];
    int bytesRead;
    long start = System.currentTimeMillis();
    while ((bytesRead = input.read(buf)) > 0)
    {
        output.write(buf, 0, bytesRead);
    }
    long end = System.currentTimeMillis();

    input.close();
    output.close();

    return (end-start);
}

private static long fileCopyUsingNIOChannelClass(File fileToCopy, File newFile) throws IOException
{
    FileInputStream inputStream = new FileInputStream(fileToCopy);
    FileChannel inChannel = inputStream.getChannel();

    FileOutputStream outputStream = new FileOutputStream(newFile);
    FileChannel outChannel = outputStream.getChannel();

    long start = System.currentTimeMillis();
    inChannel.transferTo(0, fileToCopy.length(), outChannel);
    long end = System.currentTimeMillis();

    inputStream.close();
    outputStream.close();

    return (end-start);
}

private static long fileCopyUsingApacheCommons(File fileToCopy, File newFile) throws IOException
{
    long start = System.currentTimeMillis();
    FileUtils.copyFile(fileToCopy, newFile);
    long end = System.currentTimeMillis();
    return (end-start);
}

private static long fileCopyUsingNIOFilesClass(File fileToCopy, File newFile) throws IOException
{
    Path source = Paths.get(fileToCopy.getPath());
    Path destination = Paths.get(newFile.getPath());
    long start = System.currentTimeMillis();
    Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
    long end = System.currentTimeMillis();

    return (end-start);
}

le seul inconvénient que je peux voir en utilisant la classe de canal NIO est que je n'arrive toujours pas à trouver un moyen de montrer le progrès de la copie de fichier intermédiaire.

0
répondu Vinit Shandilya 2018-05-30 10:50:52