tags:

views:

538

answers:

7

I want to copy file a.txt to newDir/ from within a scala script. In java this would be done by creating 2 file streams for the 2 files, reading into buffer from a.txt and writing it to the FileOutputStream of the new file. Is there a better way to achieve this in scala? May be something in scala.tools.nsc.io._. I searched around but could not find much.

+5  A: 

Why not use Apache Commons IO and FileUtils.copyFile() in particular ? Note that FileUtils has a large number of methods to copy files/directories etc.

Brian Agnew
Downvoted why ? Reuse of an existing component for this seems pragmatic to me.
Brian Agnew
A: 

If you don't wanna use anything external, just do it as you would have done it in Java. The nice thing, is that you can.

Geo
A: 

If you don't care too much about speed, you can make your life slightly easier by reading the file using scala.io.Source (this implementation is for 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()
}

But Source goes to all the trouble of parsing the file line by line, and then you just write it out again without actually processing the lines. Using byte read/write Java style will be considerably faster (about 2-3x last time I benchmarked it).

Rex Kerr
I might have large number of files and different types of files to copy. The files can also quite big in size. Would slurp() or any other apis in the scalax help?
kulkarni
In that case, I'd say Brian's suggestion is the right one--use the Apache Commons IO. It's made to do just what you want, and Scala is made to use Java libraries.
Rex Kerr
A: 

Scalax has scalax.io.FileExtras.copyTo(dest : File). But developement seems to have stopped.

Thomas Jung
A: 
Runtime.getRuntime.exec("cp 01.txt 02.txt", Array(): Array[String], new java.io.File(".")).waitFor

Only works on real operating systems. :D

Synesso
This is a very bad idea. You get very little visibility into errors that might happen during the process.
Alain O'Dea
It was only a lark.
Synesso
+1  A: 

If you really want to do it yourself instead of using a library like commons-io, you can do the following in version 2.8. Create a helper method "use". It will give you a form of automatic resource management.

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

Then you can define a copy method like this:

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

Note that the buffer size (here: 1024) might need some tuning.

Ruediger Keller
+2  A: 

For performance reasons it is better to use java.nio.Channel to do the copying.

Listing of copy.scala:

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

To try this out create a file called test.txt with the following content:

Hello World

After creating test.txt, run the following from the command line:

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

Verify that test-copy.txt has Hello World as its content.

Alain O'Dea
A side-benefit of my solution is that it supports binary files.A side-effect is that it ties you to Java, which is bad if you intend to run your Scala code on .NET.
Alain O'Dea
That's also much nicer code than dealing with the bytes yourself.
Marcus Downing