/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ // $Id$ package scala.io import java.io.{ FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter, BufferedInputStream, BufferedOutputStream, IOException, File => JFile } import java.nio.channels.FileChannel import collection.Traversable object File { def apply(path: Path)(implicit codec: Codec = null) = if (codec != null) new File(path.jfile)(codec) else path.toFile // Create a temporary file def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null) = apply(JFile.createTempFile(prefix, suffix, dir)) import java.nio.channels.Channel type Closeable = { def close(): Unit } def closeQuietly(target: Closeable) { try target.close() catch { case e: IOException => } } } import File._ import Path._ /** An abstraction for files. For character data, a Codec * can be supplied at either creation time or when a method * involving character data is called (with the latter taking * precdence if supplied.) If neither is available, the value * of scala.io.Codec.default is used. * * @author Paul Phillips * @since 2.8 */ class File(jfile: JFile)(implicit val creationCodec: Codec = null) extends Path(jfile) with Streamable.Chars { def withCodec(codec: Codec): File = new File(jfile)(codec) override def toDirectory: Directory = new Directory(jfile) override def toFile: File = this override def isValid = jfile.isFile() || !jfile.exists() override def length = super[Path].length /** Obtains an InputStream. */ def inputStream() = new FileInputStream(jfile) /** Obtains a OutputStream. */ def outputStream(append: Boolean = false) = new FileOutputStream(jfile, append) def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append)) /** Obtains an OutputStreamWriter wrapped around a FileOutputStream. * This should behave like a less broken version of java.io.FileWriter, * in that unlike the java version you can specify the encoding. */ def writer(append: Boolean = false, codec: Codec = getCodec()) = new OutputStreamWriter(outputStream(append), codec.charSet) /** Wraps a BufferedWriter around the result of writer(). */ def bufferedWriter(append: Boolean = false, codec: Codec = getCodec()) = new BufferedWriter(writer(append, codec)) /** Writes all the Strings in the given iterator to the file. */ def writeAll(xs: Traversable[String], append: Boolean = false, codec: Codec = getCodec()): Unit = { val out = bufferedWriter(append, codec) try xs foreach (out write _) finally out close } def copyFile(destPath: Path, preserveFileDate: Boolean = false) = { val FIFTY_MB = 1024 * 1024 * 50 val dest = destPath.toFile if (!isValid) fail("Source %s is not a valid file." format name) if (this.normalize == dest.normalize) fail("Source and destination are the same.") if (!dest.parent.map(_.exists).getOrElse(false)) fail("Destination cannot be created.") if (dest.exists && !dest.canWrite) fail("Destination exists but is not writable.") if (dest.isDirectory) fail("Destination exists but is a directory.") lazy val in_s = inputStream() lazy val out_s = dest.outputStream() lazy val in = in_s.getChannel() lazy val out = out_s.getChannel() try { val size = in.size() var pos, count = 0L while (pos < size) { count = (size - pos) min FIFTY_MB pos += out.transferFrom(in, pos, count) } } finally List[Closeable](out, out_s, in, in_s) foreach closeQuietly if (this.length != dest.length) fail("Failed to completely copy %s to %s".format(name, dest.name)) if (preserveFileDate) dest.lastModified = this.lastModified () } override def toString() = "File(%s)".format(path) }