430 Stimmen

Standardmethode zum Kopieren einer Datei in Java?

Es hat mich schon immer gestört, dass die einzige Möglichkeit, eine Datei in Java zu kopieren, darin besteht, Streams zu öffnen, einen Puffer zu deklarieren, eine Datei einzulesen, sie in einer Schleife zu durchlaufen und sie in die andere Datei zu schreiben. Das Web ist übersät mit ähnlichen, aber dennoch leicht unterschiedlichen Implementierungen dieser Art von Lösung.

Gibt es einen besseren Weg, der innerhalb der Grenzen der Java-Sprache bleibt (d.h. ohne die Ausführung von OS-spezifischen Befehlen)? Vielleicht in einem zuverlässigen Open-Source-Utility-Paket, das zumindest die zugrunde liegende Implementierung verschleiert und eine Ein-Zeilen-Lösung bietet?

280voto

Josh Punkte 16859

Ich würde die Verwendung einer Mega-Api wie Apache Commons vermeiden. Dies ist ein einfacher Vorgang, der in das JDK im neuen NIO-Paket integriert ist. Es wurde irgendwie schon in einer früheren Antwort verlinkt, aber die Schlüsselmethode in der NIO-Api sind die neuen Funktionen "transferTo" und "transferFrom".

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

Einer der verlinkten Artikel zeigt, wie man diese Funktion in den eigenen Code integrieren kann, indem man transferFrom verwendet:

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

Das Erlernen von NIO kann ein wenig knifflig sein, daher sollten Sie vielleicht erst einmal auf diese Mechanik vertrauen, bevor Sie losziehen und versuchen, NIO über Nacht zu lernen. Aus persönlicher Erfahrung kann es sehr schwierig sein, NIO zu erlernen, wenn man keine Erfahrung hat und mit IO über java.io Streams vertraut ist.

277voto

delfuego Punkte 13864

Wie das Toolkit oben erwähnt, ist Apache Commons IO der richtige Weg, insbesondere FileUtils . copyFile() ; es übernimmt alle schweren Aufgaben für Sie.

Und als Nachtrag sei angemerkt, dass neuere Versionen von FileUtils (wie die Version 2.0.1) die Verwendung von NIO zum Kopieren von Dateien hinzugefügt haben; NIO kann die Leistung beim Kopieren von Dateien erheblich steigern Dies liegt zum großen Teil daran, dass die NIO-Routinen das Kopieren direkt an das Betriebssystem/Dateisystem delegieren, anstatt es durch das Lesen und Schreiben von Bytes über die Java-Schicht zu erledigen. Wenn Sie also Wert auf Leistung legen, sollten Sie sicherstellen, dass Sie eine aktuelle Version von FileUtils verwenden.

183voto

Scott Punkte 2213

Mit Java 7 können Sie jetzt die folgende try-with-resource-Syntax verwenden:

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

Oder, noch besser, dies kann auch mit der neuen Klasse Files, die in Java 7 eingeführt wurde, erreicht werden:

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

Ganz schön schick, was?

93voto

Glen Best Punkte 22041
  • Diese Methoden sind leistungsorientiert (sie integrieren sich in die betriebssystemeigene E/A).
  • Diese Methoden funktionieren mit Dateien, Verzeichnissen und Links.
  • Jede der angegebenen Optionen kann weggelassen werden - sie sind optional.

Die Hilfsklasse

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

Kopieren eines Verzeichnisses oder einer Datei

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

Verschieben eines Verzeichnisses oder einer Datei

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

Rekursives Kopieren eines Verzeichnisses oder einer Datei

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

49voto

Kevin Sadler Punkte 2116

In Java 7 ist es einfach...

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

Files.copy(src.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X