summaryrefslogtreecommitdiff
path: root/src/library/scala/io/File.scala
blob: f1cdb452dc964cf2cb1c8b8788cf2653fa490282 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*                     __                                               *\
**     ________ ___   / /  ___     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, File => JFile }
import collection.Traversable

object File
{
  final val extensionRegex = """^.*\.([^.]+)$""".r
  implicit def fileWrapper(file: JFile): File = new File(file)

  def apply(fileName: String) = new File(new JFile(fileName))
  def apply(file: JFile)      = new File(file)

  private def randomPrefix = {
    import scala.util.Random.nextInt
    import Character.isJavaIdentifierPart

    (Iterator continually nextInt)
    . map (x => ((x % 60) + 'A').toChar)
    . filter (isJavaIdentifierPart)
    . take (6)
    . mkString
  }
  // Create a temporary file
  def tempfile(prefix: String = randomPrefix, suffix: String = null, dir: JFile = null) =
    apply(JFile.createTempFile(prefix, suffix, dir))

  // Like tempfile but creates a directory instead
  def tempdir(prefix: String = randomPrefix, suffix: String = null, dir: JFile = null) = {
    val file = tempfile(prefix, suffix, dir)
    file.delete()
    file.mkdirs()
    file
  }

}
import File._

/** An abstraction for files.  For now it is little more than a wrapper
 *  around java.io.File.
 *
 *  @author  Paul Phillips
 *  @since   2.8
 */
class File(val file: JFile)(implicit val codec: Codec = Codec.default) extends collection.Iterable[File]
{
  def name = file.getName()
  def path = file.getPath()
  def absolutePath = file.getAbsolutePath()
  def delete() = file.delete()
  def mkdirs() = file.mkdirs()
  def isFile = file.isFile()
  def canRead = file.canRead()
  def canWrite = file.canWrite()

  def isFresher(other: File) = file.lastModified > other.file.lastModified

  /** If file is a directory, an iterator over its contents.
   *  If not, an empty iterator.
   */
  def iterator: Iterator[File] =
    if (file.isDirectory) file.listFiles.iterator map (x => new File(x))
    else Iterator.empty

  /** Convenience function for iterating over the lines in the file.
   */
  def lines(): Iterator[String] = toSource().getLines()

  /** Convenience function for iterating over the bytes in a file.
   *  Note they are delivered as Ints as they come from the read() call,
   *  you can map (_.toByte) if you would really prefer Bytes.
   */
  def bytes(): Iterator[Int] = {
    val in = bufferedInput()
    Iterator continually in.read() takeWhile (_ != -1)
  }

  /** Convenience function to import entire file into a String.
   */
  def slurp() = toSource().mkString

  /** Deletes the file or directory recursively. Returns false if it failed.
   *  Use with caution!
   */
  def deleteRecursively(): Boolean = deleteRecursively(file)
  private def deleteRecursively(f: JFile): Boolean = {
    if (f.isDirectory) f.listFiles match {
      case null =>
      case xs   => xs foreach deleteRecursively
    }
    f.delete()
  }

  /** Obtains an InputStream. */
  def inputStream() = new FileInputStream(file)
  def bufferedInput() = new BufferedInputStream(inputStream())

  /** Obtains a OutputStream. */
  def outputStream(append: Boolean = false) = new FileOutputStream(file, append)
  def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append))

  /** Obtains an InputStreamReader wrapped around a FileInputStream.
   */
  def reader() =
    new InputStreamReader(inputStream, codec.charSet)

  /** 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) =
    new OutputStreamWriter(outputStream(append), codec.charSet)

  /** Wraps a BufferedReader around the result of reader().
   */
  def bufferedReader() = new BufferedReader(reader())

  /** Wraps a BufferedWriter around the result of writer().
   */
  def bufferedWriter(append: Boolean = false) = new BufferedWriter(writer(append))

  /** Writes all the Strings in the given iterator to the file. */
  def writeAll(xs: Traversable[String], append: Boolean = false): Unit = {
    val out = bufferedWriter(append)
    try xs foreach (out write _)
    finally out close
  }

  /** Attempts to return the file extension. */
  def extension = file.getName match {
    case extensionRegex(x)  => Some(x)
    case _                  => None
  }

  /** Creates a Source from this file. */
  def toSource(): Source = (Source fromFile file)(codec)

  /** Creates a new File with the specified path appended. */
  def /(child: String) = new File(new JFile(file, child))

  override def toString() = file.toString
  override def equals(other: Any) = other match {
    case x: File    => this.file == x.file
    case _          => false
  }
  override def hashCode = file.hashCode
}