Verschieben / Kopieren von Dateivorgängen in Java

70

Gibt es eine Standard-Java-Bibliothek, die allgemeine Dateivorgänge wie das Verschieben / Kopieren von Dateien / Ordnern verarbeitet?

MSumulong
quelle

Antworten:

72

So geht's mit java.nioOperationen:

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

        // previous code: destination.transferFrom(source, 0, source.size());
        // to avoid infinite loops, should be:
        long count = 0;
        long size = source.size();              
        while((count += destination.transferFrom(source, count, size-count))<size);
    }
    finally {
        if(source != null) {
            source.close();
        }
        if(destination != null) {
            destination.close();
        }
    }
}
Rigo Vides
quelle
5
Wenn die Datei vorhanden ist, wird der Inhalt angehängt oder überschrieben?
Janusz
@Rigo Dies verschiebt nur Dateien, ich kann keine Verzeichnisse verschieben
Arasu
11
Es ist erwähnenswert, dass Java 7 einfachere Kopier- / Verschiebemethoden bietet .
Tharwen
2
Gibt es einen Grund, warum File.renameTodas nicht so gut ist wie Files.move?
Erik Kaplun
4
@Erik Allik: Wenn der Vorgang fehlschlägt, erfahren Files.moveSie, warum, anstatt einfach zurückzukehren false. Und Files.movekann Bewegungen verarbeiten, die keine einfachen Umbenennungen sind, dh ein Kopieren und Löschen erfordern.
Holger
40

Noch nicht, aber das neue NIO (JSR 203) wird diese gemeinsamen Operationen unterstützen.

In der Zwischenzeit sind einige Dinge zu beachten.

File.renameTo funktioniert im Allgemeinen nur auf demselben Dateisystem-Volume. Ich betrachte dies als das Äquivalent zu einem "mv" -Befehl. Verwenden Sie es, wenn Sie können, aber für die allgemeine Unterstützung beim Kopieren und Verschieben benötigen Sie einen Fallback.

Wenn eine Umbenennung nicht funktioniert, müssen Sie die Datei tatsächlich kopieren (Löschen des Originals mit File.delete, wenn es sich um einen Verschiebungsvorgang handelt). Verwenden Sie dazu die Methoden FileChannel.transferTo oder FileChannel.transferFrom , um dies mit größter Effizienz zu erreichen . Die Implementierung ist plattformspezifisch, aber im Allgemeinen vermeiden Implementierungen beim Kopieren von einer Datei in eine andere das Hin- und Hertransportieren von Daten zwischen Kernel und Benutzerbereich, was zu einer erheblichen Effizienzsteigerung führt.

erickson
quelle
17

Überprüfen Sie heraus: http://commons.apache.org/io/

Es hat eine Kopie, und wie gesagt, das JDK hat sich bereits bewegt.

Implementieren Sie keine eigene Kopiermethode. Es schwimmen so viele da draußen ...

Pyrolistisch
quelle
Commons IO hat Einschränkungen hinsichtlich der Größe der Dateien, die kopiert werden können. Für eine Allzwecklösung wäre eine robustere Implementierung zu erwarten.
Erickson
3
Die Implementierung der eigenen Kopiermethode ist trivial und bedeutet, dass Sie nicht von einer gesamten Bibliothek abhängig sind. Sie implementieren Ihre eigenen
oxbow_lakes
17
Die Kopiermethode ist alles andere als trivial. Sie können leicht eine korrekte, die nicht mit Streams funktioniert, und eine schnelle, aber falsche mit NIO erstellen. Implementieren Sie niemals Ihre eigenen Dienstprogramme, wenn es Qualitätsbibliotheken gibt.
Pyrolistical
3
Eine Kopiermethode ist nicht trivial, und Apache Commons kann keinen allgemeinen Anwendungsfall behandeln: Informationen, die für den Hauptspeicher zu groß sind. Eine Bibliothek, die zum Verwalten von Massenspeicher vorgesehen ist, sollte Grenzen für den Speicherverbrauch haben, der der Apache Commons-Verschiebungsmethode fehlt.
Erickson
@Pyrolistical Uhh Never implement your own utilities when there are quality libraries out there.suure, wenn Sie sich nie um die Lizenzierung sorgen müssen.
b1nary.atr0phy
10

Frühere Antworten scheinen veraltet zu sein.

Javas File.renameTo () ist wahrscheinlich die einfachste Lösung für API 7 und scheint gut zu funktionieren. Seien Sie vorsichtig, es wirft keine Ausnahmen, sondern gibt wahr / falsch zurück !!!

Beachten Sie, dass es in früheren Versionen Probleme zu geben scheint (wie bei NIO ).

Wenn Sie eine frühere Version verwenden müssen, klicken Sie hier .

Hier ist ein Beispiel für API7:

File f1= new File("C:\\Users\\.....\\foo");
File f2= new File("C:\\Users\\......\\foo.old");
System.err.println("Result of move:"+f1.renameTo(f2));

Alternative:

System.err.println("Move:" +f1.toURI() +"--->>>>"+f2.toURI());
Path b1=Files.move(f1.toPath(),  f2.toPath(), StandardCopyOption.ATOMIC_MOVE ,StandardCopyOption.REPLACE_EXISTING ););
System.err.println("Move: RETURNS:"+b1);
ntg
quelle
3
Wenn die Meldung "Der Prozess kann nicht auf die Datei zugreifen, weil sie von einem anderen Prozess verwendet wird" angezeigt wird. Der Prozess kann nicht auf die Datei zugreifen, weil sie von einem anderen Prozess verwendet wird. "Ausnahme beim zweiten Codeteil: Denken Sie daran, die Datei zu schließen vor dem Verschieben .....
ntg
2
Es gibt andere unerwartete Situationen, in denen dies fehlschlägt, z. B. unter Linux, wenn Sie zwei verschiedene Dateisysteme unter / mnt / a / mnt / b gemountet haben, können Sie eine Datei / mnt / a / file1 nicht in / mnt / b / file2 umbenennen, da Es handelt sich tatsächlich um eine Verschiebungsoperation. File.renameTo würde in diesem Fall fehlschlagen.
xask
1
Dies ist die beste Lösung. Verwenden Sie einfach Files.move (), wenn Sie befürchten, dass der Umbenennungsvorgang fehlschlägt.
Xtian
7

Versuchen Sie, org.apache.commons.io.FileUtils (Allgemeine Dienstprogramme zur Dateibearbeitung ) zu verwenden. Die Einrichtungen werden auf folgende Weise bereitgestellt:

(1) FileUtils.moveDirectory (Datei srcDir, Datei destDir) => Verschiebt ein Verzeichnis.

(2) FileUtils.moveDirectoryToDirectory (Datei src, Datei destDir, boolean createDestDir) => Verschiebt ein Verzeichnis in ein anderes Verzeichnis.

(3) FileUtils.moveFile (Datei srcFile, Datei destFile) => Verschiebt eine Datei.

(4) FileUtils.moveFileToDirectory (Datei srcFile, Datei destDir, boolean createDestDir) => Verschiebt eine Datei in ein Verzeichnis.

(5) FileUtils.moveToDirectory (Datei src, Datei destDir, boolean createDestDir) => Verschiebt eine Datei oder ein Verzeichnis in das Zielverzeichnis .

Es ist einfach, leicht und schnell.

Dellanio
quelle
Sind diese Funktionen atomar?
Summe
0

Interessante Beobachtung: Es wurde versucht, dieselbe Datei über verschiedene Java-Klassen und die gedruckte Zeit in Nanosekunden zu kopieren.

Dauer mit FileOutputStream-Bytestream: 4 965 078

Dauer mit BufferedOutputStream: 1 237 206

Dauer mit (Zeichentext Reader: 2 858 875

Dauer mit BufferedReader (Textstrom für gepufferte Zeichen: 1 998 005

Dauer mit (Dateien NIO-Kopie): 18 351 115

Bei Verwendung der Datei-Nio-Kopieroption dauerte es fast 18-mal länger !!! Nio ist die langsamste Option zum Kopieren von Dateien und BufferedOutputStream scheint die schnellste zu sein. Ich habe für jede Klasse dieselbe einfache Textdatei verwendet.

Elena
quelle