Thursday, August 2, 2012

Scala-IO Core: Resource, Input

Just a note: all these examples have been tested in REPL so go ahead and fire up the sbt console in the example project and try these out.

Resource


Resource is the fundamental component of Scala-IO. A Resource is essentially anything that has a simple open/close lifecycle. The Resource trait handles the lifecycle for the developer allowing him to focus on the IO logic.

In the typical use-case one of the Resource subclasses will be used. They are more useful in general because they will have one of higher level traits mixed in like Input or Output.

The most typical way to create a Resource is with the Resource object which is a factory method for creating Resource objects from various types of Java objects.

While Resource is the foundation Trait, Input and Output are the Traits most commonly used, The user-facing traits if you will.

Here are a few examples of creating Resources:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import scalax.io.Resource
 
Resource.fromURL("http://www.camptocamp.com")
Resource.fromURL(new java.net.URL("http://www.camptocamp.com"))
 
Resource.fromFile("file")
Resource.fromFile(new java.io.File("file"))
 
Resource.fromRandomAccessFile(new java.io.RandomAccessFile("file", "rw"))
 
Resource.fromByteChannel(new java.io.FileInputStream("file").getChannel)
Resource.fromReadableByteChannel(new java.io.FileInputStream("file").getChannel)
Resource.fromWritableByteChannel(new java.io.FileInputStream("file").getChannel)
 
Resource.fromInputStream(new java.io.FileInputStream("file"))
Resource.fromOutputStream(new java.io.FileOutputStream("file"))
 
Resource.fromReader(new java.io.FileReader("file"))
Resource.fromWriter(new java.io.FileWriter("file"))
 
Resource.fromClasspath("scalax/io/Resource.class")
Resource.fromClasspath("scalax/io/Resource.class", classOf[Resource[_]])
There are advanced usages of Resource that we will get into in later posts. At the moment I want to focus on Input, Output and Seekable Traits. In later posts we will look at how to integrate with legacy Java APIs and how to access the underlying resource using the loan pattern.

Input


The Input Trait provides methods for accessing the data of the underlying resource in various different way. As bytes, strings, lines, etc...

There are two basic types of methods. Methods that return LongTraversable objects and methods that load the entire Resource into memory. For example: string and byteArray load the entire resource into memory while bytes and chars return a LongTraversable.

What is a LongTraversable? That will be the next post :-). Summarized, it is a specialized Lazy/non-strict Traversable.
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
import scalax.io._
val input:Input = Resource.fromURL("http://www.scala-lang.org")
 
// The simplest way to read data is to get the bytes from an Input object
val bytes: LongTraversable[Byte] = input.bytes
 
// you can also get the characters and strings from an Input object but you need a codec for decoding the bytes
val chars: LongTraversable[Char] = input.chars(Codec.UTF8)
 
// The default encoding is UTF-8 so one can leave of the codec if desired
val defaultChars = input.chars
 
// Notice that the () are left off input.chars.  That is because the codec
// parameter is implicit.  This allows the codec to be defined once
// and be used by all chars calls
implicit val codec = Codec.ISO8859
val iso8859chars = input.chars
 
// The read method in the java InputStream API returns the bytes
// as an integer. For the similar behaviour you can call bytesAsInts
val bytesAsInts = input.bytesAsInts
 
// There are two useful methods for loading all data into memory
val string = input.string
val array = input.byteArray
 
// We will revisit it in more detail later but there is an efficient copy method
// for copying the data from the Input object to any Output
// The copy method detects type of the Input Object and the Output
// object and intelligently chooses a method for copying that is
// as efficient as possible.
// For example if the Input is based on a FileInputStream and
// Output is based on a FileOutputStream the FileChannel copyTo
// method is used so that the OS will perform the copy
// efficiently
input copyDataTo Resource.fromFile("file")
 
// Lines Example 1
// Another useful method is the lines() method which more or less
// does what it implies.  The default behaviour will be to Auto
// detect the line ending.  For efficiency it finds the end of the first
// line and then assumes the rest of the file has the same ending. 
// The terminator is removed by default.
input.lines()
 
// Lines Example 2
// This example explicitly declares the EOL terminator and
// requests that the terminator is not stripped from the line
import Line.Terminators._
input.lines(terminator=NewLine, includeTerminator=true)
 
// Lines Example 3
// Lastly lines is not limited to just the standard line endings
// arbitrary separators can be used.  This last example
// demonstrates parsing the input into lines using %% as the
// EOL terminator.  Additionally it shows the explicit use
// of the Codec to override the in scope implicit Codec
input.lines(terminator=Custom("%%"))(Codec.UTF8)

1 comment: