Frage

Es hat mir immer gestört, dass der einzige Weg, um eine Datei in Java kopieren beinhaltet Streams, erklärt einen Puffer öffnen, in einer Datei zu lesen, Looping durch, und es aus mit dem anderen Dampf zu schreiben. Die Bahn wird übersät mit ähnlichen, aber dennoch leicht unterschiedlichen Implementierungen dieser Art von Lösung.

Gibt es eine bessere Art und Weise, die innerhalb der Grenzen der Java-Sprache bleibt (also nicht exec-ing OS-spezifische Befehle beinhaltet)? Vielleicht in einigem zuverlässigen Programm-Paket Open Source, das würde zumindest obskure diese grundlegende Implementierung und bietet eine einzeilige Lösung?

War es hilfreich?

Lösung

Als Toolkit oben erwähnt, Apache Commons IO ist der Weg zu gehen, und zwar FileUtils . copyfile () ; es kümmert sich um alle, die schweres Heben für Sie.

Und als Postscript, beachten Sie, dass neuere Versionen von FileUtils (wie der 2.0.1 Release) hat für das Kopieren von Dateien die Verwendung von NIO hinzugefügt; NIO kann Datei-Kopieren Leistung , in einem großen Teil, weil die NIO-Routinen deutlich erhöhen aufschieben direkt mit dem OS / Dateisystem zu kopieren, anstatt es handhaben durch das Lesen und Bytes durch die Java-Schicht zu schreiben. Also, wenn Sie für die Leistung suchen, könnte es sich lohnen, die Überprüfung, dass Sie eine aktuelle Version von FileUtils verwenden.

Andere Tipps

würde ich die Verwendung eines Mega-api wie Apache Commons vermeiden. Dies ist eine einfache Bedienung und seine in das JDK im neuen NIO-Paket gebaut. Es war irgendwie schon in Verbindung mit in einer früheren Antwort, 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 (lang,% 20long,% 20java.nio.channels .WritableByteChannel)

Einer der verlinkten Artikel zeigt eine gute Möglichkeit, wie diese Funktion in den Code zu integrieren, die transferFrom mit:

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

Learning NIO kann ein wenig schwierig sein, so dass Sie nur in diesem Mechaniker wollen vielleicht vertrauen, bevor sie aus und versuchen, NIO zu lernen, über Nacht. Aus eigener Erfahrung kann es eine sehr harte Sache sein zu lernen, wenn Sie IO nicht die Erfahrung haben und wurden über die java.io Ströme eingeführt.

Jetzt mit Java 7, können Sie die folgende Try-mit-Ressource 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 auch erreicht werden, kann die neuen Dateien Klasse in Java 7 eingeführt werden:

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

Pretty pfiffige, nicht wahr?

  • Diese Methoden sind Performance-Engineering (sie integrieren mit dem Betriebssystem nativen I / O).
  • arbeiten Diese Methoden mit Dateien, Verzeichnisse und Links.
  • geliefert Jede der Optionen weggelassen werden können - sie sind optional
  • .

Die Utility-Klasse

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

ein Verzeichnis verschieben oder die 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);

Kopieren eines Verzeichnisses oder einer Datei rekursiv

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

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

Um eine Datei zu kopieren und an Ihren Zielpfad speichern Sie die Methode unten verwenden können.

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

Beachten Sie, dass alle diese Mechanismen nur den Inhalt der Datei kopieren, nicht die Metadaten wie Berechtigungen. Also, wenn Sie sind nicht ausführbar sein, um eine ausführbare Datei .sh kopieren oder verschieben auf die neue Datei linux.

Um wirklich eine Kopie oder eine Datei zu verschieben, das heißt das gleiche Ergebnis wie das Kopieren von einer Befehlszeile zu erhalten, müssen Sie tatsächlich ein native Tool verwenden. Entweder ein Shell-Skript oder JNI.

Offensichtlich könnte dies 7 in Java festgelegt werden - http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html . Daumen drücken!

Google Guava Bibliothek hat auch eine Kopiermethode :

public static void copy(File from,
                        File to)
                 throws IOException
Kopiert alle Bytes aus einer Datei zur anderen.

Achtung: Wenn to eine vorhandene Datei darstellt, die Datei  wird mit dem Inhalt des from überschrieben. Wenn to und  from beziehen sich auf die gleiche Datei, um den Inhalt der Datei  wird gelöscht.

Parameter: from - die Quelle fileto - die Zieldatei

Löst aus: IOException - wenn ein I / O-Fehler auftritt, IllegalArgumentException - wenn from.equals(to)

Als Standard in 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

Ich kann nicht glauben, es dauert so lange etwas so häufig und so einfach wie das Kopieren von Dateien zu standardisieren: (

Drei mögliche Probleme mit dem obigen Code:

  1. Wenn getChannel eine Ausnahme auslöst, könnten Sie einen offenen Strom auslaufen.
  2. Für große Dateien, Sie könnten versuchen, mehr auf einmal zu übertragen, als das Betriebssystem umgehen kann.
  3. Sie ignorieren den Rückgabewert von transferFrom, so dass es möglicherweise nur einen Teil der Datei kopiert werden.

Aus diesem Grund org.apache.tools.ant.util.ResourceUtils.copyResource so kompliziert ist. Beachten Sie auch, dass, während transferFrom in Ordnung ist, transferTo bricht auf JDK 1.4 unter Linux (siehe Bug-ID: 5056395 ) - Jesse Glick Jan

Wenn Sie in einer Web-Anwendung, die bereits Spring verwendet und wenn Sie wollen nicht Apache Commons IO für einfaches Kopieren von Dateien enthalten, können Sie FileCopyUtils des Spring-Framework.

Hier drei Möglichkeiten, wie Sie können ganz einfach Dateien mit Codezeile kopieren!

Java7 :

java.nio.file.Files # kopieren

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

Guava :

Dateien # kopieren

private static void copyFileUsingGuava(File source,File dest) throws IOException{
    Files.copy(source,dest);          
}
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();
        }
    }
}

NIO Kopie mit einem Puffer ist die schnellst nach meinem Test. Siehe den Arbeitscode unten von einem Testprojekt von mir unter 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();
        }    
    }
}

}

Schnelle und Arbeit mit allen Versionen von Java auch 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();
}

Ein wenig spät, um die Partei, aber hier ist ein Vergleich der Zeit, um eine Datei mit verschiedenen Dateikopiermethoden zu kopieren. Ich geschleift für 10-mal durch die Methoden in und dauerte durchschnittlich. Dateiübertragung mit IO-Streams scheint der schlechteste Kandidat zu sein:

Hier sind die Methoden:

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

Der einzige Nachteil, was ich sehen kann, während NIO-Kanal-Klasse ist, dass ich immer noch nicht scheinen, einen Weg zu finden Zwischendatei kopieren Fortschritt zu zeigen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top