summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-09-01 15:52:47 +0000
committerPaul Phillips <paulp@improving.org>2009-09-01 15:52:47 +0000
commit0ef9dbcef0a6a77388dd5bce78282b7892192019 (patch)
tree39b16541086fdf300a56a84835ef6cb6296f5df7 /src
parent6da528df440dd72742f9e0b6773a2b79dc07d5b2 (diff)
downloadscala-0ef9dbcef0a6a77388dd5bce78282b7892192019.tar.gz
scala-0ef9dbcef0a6a77388dd5bce78282b7892192019.tar.bz2
scala-0ef9dbcef0a6a77388dd5bce78282b7892192019.zip
Factored the InputStream-based implementations ...
Factored the InputStream-based implementations out of File into scala.io.Streamable, where they will eventually be reused by Source.
Diffstat (limited to 'src')
-rw-r--r--src/dotnet-library/scala/io/Streamable.scala1
-rw-r--r--src/library/scala/io/File.scala71
-rw-r--r--src/library/scala/io/Path.scala2
-rw-r--r--src/library/scala/io/Streamable.scala110
4 files changed, 119 insertions, 65 deletions
diff --git a/src/dotnet-library/scala/io/Streamable.scala b/src/dotnet-library/scala/io/Streamable.scala
new file mode 100644
index 0000000000..ff90ea3bbb
--- /dev/null
+++ b/src/dotnet-library/scala/io/Streamable.scala
@@ -0,0 +1 @@
+/* Streamable.scala does not exist for the dotnet target */ \ No newline at end of file
diff --git a/src/library/scala/io/File.scala b/src/library/scala/io/File.scala
index f4683820d8..0b070868c1 100644
--- a/src/library/scala/io/File.scala
+++ b/src/library/scala/io/File.scala
@@ -18,10 +18,9 @@ import collection.Traversable
object File
{
- def apply(path: Path)(implicit codec: Codec = null) = {
- val res = path.toFile
- if (codec == null) res else res withCodec codec
- }
+ 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) =
@@ -40,74 +39,22 @@ import Path._
*/
class File(jfile: JFile)(implicit val creationCodec: Codec = null)
extends Path(jfile)
+with Streamable.Chars
{
- private def getCodec(): Codec =
- if (creationCodec == null) Codec.default else creationCodec
-
- /** For explicitly setting the creation codec if necessary.
- */
- def withCodec(codec: Codec) = new File(jfile)(codec)
-
+ def withCodec(codec: Codec): File = new File(jfile)(codec)
override def toDirectory: Directory = new Directory(jfile)
override def toFile: File = this
+
override def create(): Boolean = jfile.createNewFile()
override def isValid = jfile.isFile() || !jfile.exists()
-
- /** Convenience functions for iterating over the bytes in a file.
- */
- def bytesAsInts(): Iterator[Int] = {
- val in = bufferedInput()
- Iterator continually in.read() takeWhile (_ != -1)
- }
- /** This one is intended as the fast way.
- */
- def toByteArray(): Array[Byte] = {
- val arr = new Array[Byte](length.toInt)
- val len = arr.length
- lazy val in = bufferedInput()
- var offset = 0
-
- try {
- def loop() {
- if (offset < len) {
- val read = in.read(arr, offset, len - offset)
- if (read >= 0) {
- offset += read
- loop()
- }
- }
- }
- loop()
-
- if (offset == arr.length) arr
- else fail("Could not read entire file '%s' (%d of %d bytes)".format(name, offset, len))
- }
- finally in.close()
- }
- def bytes(): Iterator[Byte] = bytesAsInts() map (_.toByte)
- def chars(codec: Codec = getCodec()) = (Source fromFile jfile)(codec)
-
- /** Convenience function for iterating over the lines in the file.
- */
- def lines(codec: Codec = getCodec()): Iterator[String] = chars(codec).getLines()
-
- /** Convenience function to import entire file into a String.
- */
- def slurp(codec: Codec = getCodec()) = chars(codec).mkString
+ override def length = super[Path].length
/** Obtains an InputStream. */
def inputStream() = new FileInputStream(jfile)
- def bufferedInput() = new BufferedInputStream(inputStream())
/** Obtains a OutputStream. */
def outputStream(append: Boolean = false) = new FileOutputStream(jfile, append)
def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append))
- // def channel(append: Boolean = false) = outputStream(append).getChannel()
-
- /** Obtains an InputStreamReader wrapped around a FileInputStream.
- */
- def reader(codec: Codec = getCodec()) =
- new InputStreamReader(inputStream, codec.charSet)
/** Obtains an OutputStreamWriter wrapped around a FileOutputStream.
* This should behave like a less broken version of java.io.FileWriter,
@@ -116,10 +63,6 @@ extends Path(jfile)
def writer(append: Boolean = false, codec: Codec = getCodec()) =
new OutputStreamWriter(outputStream(append), codec.charSet)
- /** Wraps a BufferedReader around the result of reader().
- */
- def bufferedReader(codec: Codec = getCodec()) = new BufferedReader(reader(codec))
-
/** Wraps a BufferedWriter around the result of writer().
*/
def bufferedWriter(append: Boolean = false, codec: Codec = getCodec()) =
diff --git a/src/library/scala/io/Path.scala b/src/library/scala/io/Path.scala
index 319cdb9898..d5fde5d410 100644
--- a/src/library/scala/io/Path.scala
+++ b/src/library/scala/io/Path.scala
@@ -34,7 +34,7 @@ import util.Random.nextASCIIString
object Path
{
- // not sure whether this will be problematic
+ // not certain these won't be problematic, but looks good so far
implicit def string2path(s: String): Path = apply(s)
implicit def jfile2path(jfile: JFile): Path = apply(jfile)
diff --git a/src/library/scala/io/Streamable.scala b/src/library/scala/io/Streamable.scala
new file mode 100644
index 0000000000..b35b40fe04
--- /dev/null
+++ b/src/library/scala/io/Streamable.scala
@@ -0,0 +1,110 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.io
+
+import java.io.{ BufferedInputStream, InputStream, PrintStream, File => JFile }
+import java.io.{ BufferedReader, InputStreamReader }
+import java.net.{ URI, URL }
+
+import collection.mutable.ArrayBuffer
+import Path.fail
+
+/** Traits for objects which can be represented as Streams.
+ *
+ * @author Paul Phillips
+ * @since 2.8
+ */
+
+object Streamable
+{
+ /** Traits which can be viewed as a sequence of bytes. Source types
+ * which know their length should override def length: Long for more
+ * efficient method implementations.
+ */
+ trait Bytes {
+ def inputStream(): InputStream
+ def length: Long = -1
+
+ def bufferedInput() = new BufferedInputStream(inputStream())
+ def bytes(): Iterator[Byte] = bytesAsInts() map (_.toByte)
+ def bytesAsInts(): Iterator[Int] = {
+ val in = bufferedInput()
+ Iterator continually in.read() takeWhile (_ != -1)
+ }
+
+ /** This method aspires to be the fastest way to read
+ * a stream of known length into memory.
+ */
+ def toByteArray(): Array[Byte] = {
+ // if we don't know the length, fall back on relative inefficiency
+ if (length == -1L)
+ return (new ArrayBuffer[Byte]() ++ bytes()).toArray
+
+ val arr = new Array[Byte](length.toInt)
+ val len = arr.length
+ lazy val in = bufferedInput()
+ var offset = 0
+
+ def loop() {
+ if (offset < len) {
+ val read = in.read(arr, offset, len - offset)
+ if (read >= 0) {
+ offset += read
+ loop()
+ }
+ }
+ }
+ try loop()
+ finally in.close()
+
+ if (offset == arr.length) arr
+ else fail("Could not read entire source (%d of %d bytes)".format(offset, len))
+ }
+ }
+
+ /** For objects which can be viewed as Chars. The abstract creationCodec
+ * can safely be defined as null and will subsequently be ignored.
+ */
+ trait Chars extends Bytes {
+ def creationCodec: Codec
+ private def failNoCodec() = fail("This method requires a Codec to be chosen explicitly.")
+
+ /** The general algorithm for any call to a method involving byte<->char
+ * transformations is: if a codec is supplied (explicitly or implicitly),
+ * use that; otherwise if a codec was defined when the object was created,
+ * use that; otherwise, use Codec.default.
+ *
+ * Note that getCodec takes a codec argument rather than having methods
+ * always default to getCodec() and use the argument otherwise, so that
+ * method implementations can, where desired, identify the case where no
+ * codec was ever explicitly supplied. If allowDefault = false, an
+ * exception will be thrown rather than falling back on Codec.default.
+ */
+ def getCodec(givenCodec: Codec = null, allowDefault: Boolean = true) =
+ if (givenCodec != null) givenCodec
+ else if (creationCodec != null) creationCodec
+ else if (allowDefault) Codec.default
+ else failNoCodec()
+
+ def chars(codec: Codec = getCodec()): Source = (Source fromInputStream inputStream())(codec)
+ def lines(codec: Codec = getCodec()): Iterator[String] = chars(codec).getLines()
+
+ /** Obtains an InputStreamReader wrapped around a FileInputStream.
+ */
+ def reader(codec: Codec = getCodec()) = new InputStreamReader(inputStream, codec.charSet)
+
+ /** Wraps a BufferedReader around the result of reader().
+ */
+ def bufferedReader(codec: Codec = getCodec()) = new BufferedReader(reader(codec))
+
+ /** Convenience function to import entire file into a String.
+ */
+ def slurp(codec: Codec = getCodec()) = chars(codec).mkString
+ }
+} \ No newline at end of file