2010-02-08 3 views
25

Я хочу скопировать файл a.txt в newDir/из скрипта scala. В java это было бы сделано путем создания 2 потоков файлов для 2-х файлов, чтения в буфер из a.txt и записи его в FileOutputStream нового файла. Есть ли лучший способ достичь этого в scala? Может быть что-то в scala.tools.nsc.io._. Я искал вокруг, но не мог найти много.Scala скрипт для копирования файлов

ответ

32

Почему не использовать Apache Commons IO и FileUtils.copyFile()? Обратите внимание, что FileUtils имеет большое количество методов для копирования файлов/каталогов и т. Д.

+10

Downvoted why? Повторное использование существующего компонента для меня кажется прагматичным для меня. –

+1

я могу думать двум причинам: это не идиоматическое Scala, ссылка не работает, и он вводит 181 KB зависимость от вашего проекта за то, что может быть записано в меньшем количестве, чем 10 строк кода (правда, что один спорный вопрос). Но наиболее важный ответ ниже показывает, как это сделать со встроенным java.nio. –

+0

Ссылка исправлена. Что касается введения зависимости 181Kb, я бы не стал волноваться. Кроме того, вполне вероятно, что либо вы используете такие библиотеки уже, и я определенно исследую такие библиотеки для таких утилит, как это, вместо того, чтобы собрать вашу собственную библиотеку «утилиты», которая делает что-то подобное. –

1

Если вы не хотите использовать что-либо внешнее, просто сделайте это так, как вы бы сделали это на Java. Самое приятное, это то, что вы можете.

2

Если вы не заботитесь слишком много о скорости, вы можете сделать вашу жизнь немного легче, читая файл, используя scala.io.Source (эта реализация для 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() 
} 

Но Источником становится все неприятность в разборе файла по строкам, а затем вы просто записываете его снова, не обрабатывая строки. Использование байта для чтения/записи Java-стиля будет значительно быстрее (примерно 2-3 раза в последний раз, когда я сравнивал его).


Редактировать: 2.8 ест новую строку, поэтому вам нужно добавить их обратно в запись.

+0

У меня может быть большое количество файлов и копий разных типов файлов. Файлы также могут иметь большой размер. Помогла бы slurp() или любой другой apis в скайлаксе? – kulkarni

+0

В этом случае я бы сказал, что предложение Брайана является правильным - использовать Apache Commons IO. Это сделано для того, чтобы сделать то, что вы хотите, и Scala используется для использования библиотек Java. –

+1

-1. Выгружает новые строки в моей системе. – aioobe

0

Scalax имеет scalax.io.FileExtras.copyTo (dest: File). Но развитие, похоже, прекратилось.

+0

Ссылка мертва ... –

9

Если вы действительно хотите сделать это самостоятельно, вместо использования библиотеки, такой как commons-io, вы можете сделать следующее в версии 2.8. Создайте вспомогательный метод «use». Это даст вам форму автоматического управления ресурсами.

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

Затем вы можете определить метод копирования, как это:

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 , _) } 
    } 
    } 
} 

Обратите внимание, что размер буфера (здесь: 1024), возможно, потребуется некоторые настройки.

+1

IMO, решение nio.Channel намного проще –

+0

Этот подход применим для многих других типов потоков. –

+0

nio действительно проще, но этот фрагмент настолько крут! Классическая скала. –

36

Для удобства использования лучше использовать java.nio.Channel, чтобы сделать копирование.

Листинг 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) 

Чтобы попробовать это создать файл с именем test.txt со следующим содержанием:

Hello World 

После создания test.txt, выполните следующую команду из командной строки:

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

Проверьте, что test-copy.txt содержит Hello World в своем содержании.

+0

Побочным преимуществом моего решения является то, что он поддерживает двоичные файлы. Побочным эффектом является то, что он связывает вас с Java, что плохо, если вы намереваетесь запустить свой Scala-код на .NET. –

+1

Это также гораздо более приятный код, чем для самих байтов. –

+1

Это отличный ответ и должен быть принятым решением IMO. Следует отметить, что вам может потребоваться вызвать 'dest.createNewFile', поскольку FileInputStream завершится с ошибкой, если dest не существует. Кроме того, вам может понадобиться 'dest.getCanonicalFile.getParentFile.mkdirs' для создания любых родительских каталогов файла dest. – Synesso

19

Java 7 теперь отсутствует, и у вас есть другой вариант: java.nio.file.Files.copy. Вероятно, самое простое решение (и с Scalas superior import еще проще).При условии, что from и to являются строками, как в вашем вопросе:

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) 

Конечно, вы должны начать использовать java.nio.file.Paths вместо строк.

2

Hire sbt.IO. Это чистая scala, она может копировать только измененные файлы, имеет полезные подпрограммы, такие как copyDirectory, delete, listFiles и т. Д. Вы можете использовать его следующим образом:

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

Примечание Вы должны добавить правильную зависимость:

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

EDIT: На самом деле это не хороший подход, поскольку зависимость "org.scala-sbt" % "io" % "version" была составлена ​​с использованием конкретного Scala и на данный момент вы не можете использовать его с версией scrag 2.10.X. Но, возможно, в будущем вы сможете добавить двойную %% в свою зависимость, например "org.scala-sbt" %% "io" % "version", и она будет работать ...

Смежные вопросы