Moyen concis standard de copier un fichier en Java?


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

Existe-t-il un meilleur moyen de rester dans les limites du langage Java (la signification n'implique pas l'exécution de commandes spécifiques au système d'exploitation)? Peut être dans un utilitaire open source fiable package, qui masquerait au moins cette implémentation sous-jacente et fournirait une solution d'une ligne?

Author: Peter, 2008-09-20

16 answers

Comme toolkit le mentionne ci-dessus, Apache Commons IO est la voie à suivre, en particulierFileUtils . copyFile(); il gère tout le travail lourd pour vous.

Et en 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 considérablement les performances de copie de fichiers, en grande partie parce que les routines NIO reportent la copie directement sur le système d'exploitation / système de fichiers plutôt que de et écrire des octets à travers la couche Java. Donc, si vous recherchez des performances, il peut être utile de vérifier que vous utilisez une version récente de FileUtils.

 268
Author: delfuego, 2016-06-28 01:43:34

J'éviterais l'utilisation d'une méga api comme apache commons. Il s'agit d'une opération simpliste et intégrée au JDK dans le nouveau package 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 "transferFrom".

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

L'un des articles liés montre un excellent moyen d'intégrer cette fonction dans votre code, en utilisant le 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();
        }
    }
}

Apprendre NIO peut être un peu délicat, donc vous voudrez peut-être simplement faire confiance à ce mécanicien avant de partir et d'essayer d'apprendre NIO du jour au lendemain. D'après votre expérience personnelle, il peut être très difficile d'apprendre si vous n'avez pas l'expérience et que vous avez été présenté à IO via le java.io flux.

 273
Author: Josh, 2011-08-15 13:15:06

Maintenant avec Java 7, vous pouvez utiliser les essayer-avec-des ressources de la syntaxe:

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 également être accompli en utilisant la nouvelle classe Files introduite dans Java 7:

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

Assez chic, hein?

 178
Author: Scott, 2011-07-29 23:01:52
  • Ces méthodes sont conçues pour les 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;
    }
}

Copie d'un répertoire ou d'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);

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

Copie récursive d'un répertoire ou d'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
Author: 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
Author: Kevin Sadler, 2014-06-21 08:20:48

À 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
Author: Rakshi, 2015-09-28 20:54:48

Notez que tous ces mécanismes ne copient que le contenu du fichier, pas les métadonnées telles que les autorisations. Donc, si vous copiez ou déplacez un fichier exécutable .sh fichier sur linux 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 la copie à partir d'une ligne de commande, vous devez réellement utiliser un outil natif. Soit un script shell ou JNI.

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

 24
Author: brad, 2008-09-23 03:38:29

La bibliothèque Goyava de Google a également une méthode de copie :

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

Avertissement: Si to représente un fichier existant, le fichier sera remplacé par le contenu de from. Si to et from reportez-vous à la meme fichier, le contenu de ce fichier seront supprimés.

Paramètres:from - le fichier sourceto - la destination fichier

Jette: IOException - si une erreur d'E/S se produit IllegalArgumentException si from.equals(to)

 21
Author: Andrew McKinlay, 2017-02-26 20:05:28

Disponible en standard dans 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 n'arrive pas à croire qu'il leur ait fallu autant de temps pour standardiser quelque chose d'aussi commun et simple que la copie de fichiers: (

 19
Author: Ryan, 2010-06-01 08:33:44

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

  1. Si getChannel lève une exception, vous risquez de fuir un flux ouvert.
  2. Pour les fichiers volumineux, vous essayez peut-être de transférer plus à la fois que ce que le système d'exploitation peut gérer.
  3. Vous ignorez la valeur de retour de transferFrom, il se peut donc qu'il ne copie qu'une partie du fichier.

C'est pourquoi org.apache.tools.ant.util.ResourceUtils.copyResource est tellement compliqué. Notez également que si transferFrom est OK, transferTo se casse sur JDK 1.4 sous Linux (voir Bug ID: 5056395{[13]–) - Jesse Glick Jan

 7
Author: saji, 2012-04-17 21:18:46

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

 7
Author: Balaji Paulrajan, 2012-09-07 06:43:50

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

Java7:

Java.nio.fichier.Les fichiers#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 :

Les Fichiers#copie

private static void copyFileUsingGuava(File source,File dest) throws IOException{
    Files.copy(source,dest);          
}
 6
Author: 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
Author: user3200607, 2014-01-16 01:25:45

Rapide et fonctionne 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
Author: user1079877, 2013-11-14 09:43:21

La copie NIO avec un tampon est la plus rapide selon mon test. Voir le code de travail ci-dessous d'un projet de test à 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
Author: Tony, 2015-02-07 22:57:44

Un peu tard 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 parcouru les méthodes 10 fois et pris une moyenne. Le transfert de fichiers à l'aide de flux IO semble être le pire candidat:

Comparaison du transfert de fichiers en utilisant différentes méthodes

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 d'afficher la progression de la copie de fichier intermédiaire.

 0
Author: Vinit Shandilya, 2018-05-30 10:50:52