2010-02-08 23 views
25

Quiero copiar el archivo a.txt a newDir/desde dentro de un script scala. En Java esto se haría creando 2 cadenas de archivos para los 2 archivos, leyendo en el búfer desde a.txt y escribiéndolo en FileOutputStream del nuevo archivo. ¿Hay una mejor manera de lograr esto en Scala? Puede ser algo en scala.tools.nsc.io._. Busqué pero no pude encontrar mucho.Script Scala para copiar archivos

Respuesta

32

¿Por qué no utilizar Apache Commons IO y FileUtils.copyFile() en particular? Tenga en cuenta que FileUtils tiene una gran cantidad de métodos para copiar archivos/directorios, etc.

+10

Downvoted why? La reutilización de un componente existente para esto me parece pragmática. –

+1

Puedo pensar en un par de razones: no es idiomático Scala, el enlace está roto, y presenta una dependencia de 181 KB en su proyecto para algo que podría escribirse en menos de 10 líneas de código (sin duda, eso es debatible). Pero lo más destacado es que la respuesta a continuación demuestra cómo lograr esto con java.nio incorporado. –

+0

Enlace fijo. En cuanto a la introducción de una dependencia de 181 Kb, realmente no me preocuparía. Además, es bastante probable que ya estés usando esas librerías, y definitivamente investigaría esas bibliotecas para utilidades como esta, en lugar de armar tu propia biblioteca de 'utilidad' haciendo algo similar. –

1

Si no desea utilizar nada externo, simplemente hágalo como lo hubiera hecho en Java. Lo bueno, es que puedes.

2

Si no se preocupan demasiado por la velocidad, puede hacer su vida un poco más fácil mediante la lectura del archivo usando scala.io.Source (esta aplicación es para 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() 
} 

Pero Source se toma la molestia de analizar el archivo línea por línea, y luego lo vuelve a escribir sin procesar las líneas. El uso de byte de lectura/escritura del estilo de Java será considerablemente más rápido (alrededor de 2-3x la última vez que lo comparé).


Editar: 2.8 come nuevas líneas, por lo que debe volver a agregarlas a la escritura.

+0

Podría tener una gran cantidad de archivos y diferentes tipos de archivos para copiar. Los archivos también pueden ser bastante grandes. ¿Podría sorber() o cualquier otra apis en Scalax ayuda? – kulkarni

+0

En ese caso, yo diría que la sugerencia de Brian es la correcta: use el Apache Commons IO. Está hecho para hacer exactamente lo que usted desea, y Scala está hecho para usar bibliotecas Java. –

+1

-1. Desordena nuevas líneas en mi sistema. – aioobe

0

Scalax tiene scalax.io.FileExtras.copyTo (dest: File). Pero el desarrollo parece haberse detenido.

+0

El enlace está muerto ... –

9

Si realmente desea hacerlo usted mismo en lugar de utilizar una biblioteca como commons-io, puede hacer lo siguiente en la versión 2.8. Crea un método de ayuda "uso". Le dará una forma de administración automática de recursos.

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

A continuación, se puede definir un método de copia de esta manera:

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

Tenga en cuenta que el tamaño del búfer (en este caso 1024) podría necesitar algunos ajustes.

+1

IMO, la solución nio.Channel es mucho más simple –

+0

este enfoque se puede utilizar en muchos más tipos de flujos –

+0

La nio es de hecho más simple, ¡pero este fragmento es tan genial! Classic Scala. –

36

Por motivos de rendimiento, es mejor utilizar java.nio.Channel para realizar la copia.

Listado de 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) 

Para probar esto crea un archivo llamado test.txt con el siguiente contenido:

Hello World 

Después de crear test.txt, ejecute lo siguiente desde la línea de comando:

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

Compruebe que test-copy.txt tiene Hello World como contenido.

+0

Una ventaja secundaria de mi solución es que admite archivos binarios. Un efecto secundario es que lo ata a Java, lo cual es malo si tiene la intención de ejecutar su código Scala en .NET. –

+1

También es un código mucho mejor que tratar con los bytes usted mismo. –

+1

Esta es una gran respuesta y debería ser la solución aceptada OMI. Una cosa a tener en cuenta es que puede necesitar llamar a 'dest.createNewFile' ya que FileInputStream fallará si el destino no existe. Además, puede necesitar 'dest.getCanonicalFile.getParentFile.mkdirs' para crear cualquier directorio padre del archivo dest. – Synesso

19

Java 7 ya está disponible y tiene otra opción: java.nio.file.Files.copy. La solución probablemente más fácil (y con Scalas superior import incluso más fácil).Siempre que from y to son cadenas como en su pregunta:

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) 

supuesto, usted debe comenzar a usar java.nio.file.Paths en lugar de cadenas.

-1

De scala-io documentation:

import scalax.io._ 
import Resource._ 

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

scala-io parece un proyecto muerto – Phil

2

Alquiler sbt.IO. Es pura scala, solo puede copiar archivos modificados, tiene rutinas útiles como copyDirectory, delete, listFiles etc. Se puede utilizar de la siguiente manera:

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

Nota debe agregar la dependencia apropiada:

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

EDITAR: En realidad esto no es un buen sistema puesto que la dependencia "org.scala-sbt" % "io" % "version" fue compilado usando particular, Scala versión y por ahora no se puede usar con la versión 2.10.X scala. Pero quizás en el futuro pueda agregar el doble %% en su dependencia como "org.scala-sbt" %% "io" % "version" y funcionará ...

Cuestiones relacionadas