2010-02-08 12 views
25

Ich möchte die Datei a.txt nach newDir/aus einem Scala-Skript kopieren. In Java würde dies getan werden, indem 2 Dateiströme für die 2 Dateien erstellt werden, die aus a.txt in den Puffer eingelesen und in den FileOutputStream der neuen Datei geschrieben werden. Gibt es einen besseren Weg, dies in Scala zu erreichen? Kann etwas in scala.tools.nsc.io._ sein. Ich suchte herum, konnte aber nicht viel finden.Scala-Skript zum Kopieren von Dateien

Antwort

32

Warum nicht Apache Commons IO und FileUtils.copyFile() insbesondere verwenden? Beachten Sie, dass FileUtils eine große Anzahl an Methoden zum Kopieren von Dateien/Verzeichnissen usw. hat.

+10

Downvoted warum? Die Wiederverwendung einer vorhandenen Komponente erscheint mir pragmatisch. –

+1

Ich kann mir ein paar Gründe vorstellen: Es ist nicht idiomatisch Scala, die Verbindung ist unterbrochen, und es führt eine 181 KB-Abhängigkeit von Ihrem Projekt für etwas, das in weniger als 10 Zeilen Code geschrieben werden könnte (zugegebenermaßen das ist fraglich). Vor allem aber zeigt die folgende Antwort, wie man dies mit eingebautem java.nio erreicht. –

+0

Link festgelegt. Was die Einführung einer 181Kb-Abhängigkeit angeht, würde ich mir keine Sorgen machen. Außerdem ist es ziemlich wahrscheinlich, dass Sie entweder solche Bibliotheken bereits verwenden, und ich würde definitiv solche Bibliotheken nach Dienstprogrammen wie diesem untersuchen, anstatt Ihre eigene 'Dienstprogramm'-Bibliothek zusammenzustellen. –

1

Wenn Sie nichts Externes verwenden möchten, tun Sie es einfach so, wie Sie es in Java getan hätten. Das Schöne ist, dass du es kannst.

2

Wenn Sie nicht zu viel kümmern uns um Geschwindigkeit, können Sie Ihr Leben etwas leichter machen, indem Sie die Datei zu lesen mit scala.io.Source (diese Implementierung ist für 2.7.7):

def copyF(from: java.io.File, to: String) { 
    val out = new java.io.BufferedWriter(new java.io.FileWriter(to)); 
    io.Source.fromFile(from).getLines.foreach(s => out.write(s,0,s.length)); 
    out.close() 
} 

Aber Source geht alle Probleme auf, die Datei Zeile für Zeile zu analysieren, und dann schreiben Sie sie einfach erneut aus, ohne die Zeilen tatsächlich zu verarbeiten. Mit Byte lesen/schreiben Java-Stil wird erheblich schneller (ca. 2-3x beim letzten Mal ich es Benchmarking).


Edit: 2.8 isst Zeilenumbrüche, so müssen Sie sie wieder in den schreiben.

+0

Ich habe möglicherweise eine große Anzahl von Dateien und verschiedene Arten von Dateien zu kopieren. Die Dateien können auch ziemlich groß sein. Würde slurp() oder irgendeine andere apis in der scalax helfen? – kulkarni

+0

In diesem Fall würde ich sagen, Brians Vorschlag ist der richtige - benutze Apache Commons IO. Es ist gemacht, um genau das zu tun, was Sie wollen, und Scala ist dafür gemacht, Java-Bibliotheken zu verwenden. –

+1

-1. Vermummt neue Zeilen auf meinem System. – aioobe

0

Scalax hat scalax.io.FileExtras.copyTo (Ziel: Datei). Aber die Entwicklung scheint aufgehört zu haben.

+0

Link ist tot ... –

9

Wenn Sie es wirklich selbst tun möchten, anstatt eine Bibliothek wie commons-io zu verwenden, können Sie in Version 2.8 Folgendes tun. Erstellen Sie eine Hilfsmethode "verwenden". Es wird Ihnen eine Form der automatischen Ressourcenverwaltung geben.

def use[T <: { def close(): Unit }](closable: T)(block: T => Unit) { 
    try { 
    block(closable) 
    } 
    finally { 
    closable.close() 
    } 
} 

Dann können Sie eine Kopie Methode wie folgt definieren:

import java.io._ 

@throws(classOf[IOException]) 
def copy(from: String, to: String) { 
    use(new FileInputStream(from)) { in => 
    use(new FileOutputStream(to)) { out => 
     val buffer = new Array[Byte](1024) 
     Iterator.continually(in.read(buffer)) 
      .takeWhile(_ != -1) 
      .foreach { out.write(buffer, 0 , _) } 
    } 
    } 
} 

Beachten Sie, dass die Puffergröße (hier: 1024) könnte einige Tuning benötigen.

+1

IMO, die nio.Channel Lösung ist viel einfacher –

+0

dieser Ansatz ist für viele weitere Arten von Streams –

+0

Das nio ist in der Tat einfacher, aber dieser Ausschnitt ist so cool! Klassische Scala. –

36

Aus Leistungsgründen ist es besser, java.nio.Channel für das Kopieren zu verwenden.

Eintrag von copy.scala:

import java.io.{File,FileInputStream,FileOutputStream} 
val src = new File(args(0)) 
val dest = new File(args(1)) 
new FileOutputStream(dest) getChannel() transferFrom(
    new FileInputStream(src) getChannel, 0, Long.MaxValue) 

Um dies zu versuchen, um eine Datei test.txt mit folgendem Inhalt erstellen:

Hello World 

Nach dem Erstellen test.txt, führen Sie Folgendes über die Befehlszeile aus:

scala copy.scala test.txt test-copy.txt 

Überprüfen Sie, dass test-copy.txtHello World als Inhalt hat.

+0

Ein Nebeneffekt meiner Lösung ist, dass es Binärdateien unterstützt. Ein Nebeneffekt ist, dass es Sie mit Java verbindet, was schlecht ist, wenn Sie beabsichtigen, Ihren Scala-Code auf .NET auszuführen. –

+1

Das ist auch viel schöner Code als mit den Bytes selbst zu tun. –

+1

Dies ist eine großartige Antwort und sollte die akzeptierte Lösung IMO sein. Beachten Sie, dass Sie "dest.createNewFile" aufrufen müssen, da FileInputStream fehlschlägt, wenn das Ziel nicht existiert. Außerdem können Sie 'dest.getCanonicalFile.getParentFile.mkdirs' benötigen, um übergeordnete Verzeichnisse der Zieldatei zu erstellen. – Synesso

19

Java 7 ist jetzt out und Sie haben eine andere Option: java.nio.file.Files.copy. Die wahrscheinlich einfachste Lösung (Und mit Scalas superior import noch einfacher).Vorausgesetzt, dass from und to sind Strings wie in Ihrer Frage:

import java.nio.file.StandardCopyOption.REPLACE_EXISTING 
import java.nio.file.Files.copy 
import java.nio.file.Paths.get 

implicit def toPath (filename: String) = get(filename) 

copy (from, to, REPLACE_EXISTING) 

Natürlich sollten Sie mit java.nio.file.Paths statt Strings beginnen.

-1

Von scala-io documentation:

import scalax.io._ 
import Resource._ 

fromFile("a.txt") copyDataTo fromFile("newDir/a.txt") 
+0

scala-io sieht aus wie ein totes Projekt – Phil

2

Vermietung sbt.IO. Es ist reine Scala, es kann nur geänderte Dateien kopieren, hat nützliche Routinen wie copyDirectory, delete, listFiles etc. Sie können es wie folgt verwendet werden:

libraryDependencies += "org.scala-sbt" % "io" % "0.13.0"

EDIT: Eigentlich ist dies kein guter Ansatz "org.scala-sbt" % "io" % "version" kompiliert wurde mit besonderem scala seit Abhängigkeit

import sbt._ 
IO.copyFile(file1, file2) 

Hinweis Sie richtige Abhängigkeit hinzufügen sollten Version und für jetzt können Sie es nicht mit 2.10.X Scala-Version verwenden. Aber vielleicht können Sie in Zukunft doppelte %% in Ihrer Abhängigkeit wie "org.scala-sbt" %% "io" % "version" hinzufügen und es wird funktionieren ...

Verwandte Themen