Wednesday, August 8, 2012

Scala-IO Core: Output

The Output object is the primary trait for writing data to a resource. The basic usage is very simple but can get more complex when one wishes to serialize objects.

Lets start with the basic usage:
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
import scalax.io._
import scalax.io.Resource
 
val out:Output = Resource.fromOutputStream(new java.io.FileOutputStream("daily-scala.out"))
val in:Input = Resource.fromFile("daily-scala.out")
 
// Write some bytes to the output object
// each write will typically overwrite
//the previous data the processing API
// can be used is you do not want this behaviour
out write "data".getBytes()
out write Array[Byte](1,2,3)
 
// print out file in REPL
in.byteArray
 
// Writing strings need a Codec
// for encoding the strings.  The default is UTF8
// but the default is easily overridden.
out write "howdy"
 
// printout file in REPL
in.string
 
out.write("howdy")(Codec.UTF8)
 
// printout file in REPL
in.string
 
implicit val defaultCodec: Codec = Codec.UTF8
 
// The implicit code will be used instead of the
// default codec
out write "hi there"
 
// printout file in REPL
in.string
 
// write all strings in a collection with default separator ("")
out writeStrings Seq("it","was","a","dark","and","stormy","night")
 
// printout file in REPL
in.string
 
// write all strings in sequence with a space as the separator
out.writeStrings(Seq("it","was","a","dark","and","stormy","night"), " ")
A common need is to write several times to a single Output without overwriting the data. To do this one can use the processing API. A future post(s) will look at the processing API in more detail but for now a simple example:
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
import scalax.io._
 
val output:Output = Resource.fromOutputStream(new java.io.FileOutputStream("daily-scala.out"))
val in:Input = Resource.fromFile("daily-scala.out")
 
// Output processor are used when one
// needs to perform batch writes on an
// output object When a processor object
// is used a "processing" pipeline is
// created and the operations are performed
// in batch form.
 
// The following example will write 2 lines
// to the output object (a file in this case)
// there are a few ways to use outputProcessors. 
 
// This example is the pattern most developers will
// likely be most comfortable with:
for{
  // create a processor (signalling the start of a batch process)
  processor <- output.outputProcessor
  // create an output object from it
  out = processor.asOutput
}{
  // all writes to out will be on the same open output stream/channel
  out.write("first write\n")
  out.write("second write")
}
 
// show data in REPL
in.string
 
// As will be shown in the future, a processor is typically lazy
// if created with map and flatmap calls.
// The next example is another way to do the multiple writes.
 
// first create processor
val processor = for{
    // create the processor
    out <- output.outputProcessor
    // perform write calls
    _ <- out.write("second time first write\n")
    _ <- out.write("second time second write")
} yield {}
// at this point the writes have not occurred because
// processor contains the processing pipeline
 
// show data in REPL
in.string
 
processor.execute  // execute processor
 
// show data in REPL
in.string

5 comments:

  1. in.string is not working. Should it be in.slurpString?

    ReplyDelete
    Replies
    1. As I have been writing the daily-scala posts the name slurpString was starting to bother me because it did not conform to the other methods. All the other methods (like byteArray) are dry boring names and slurpString didn't conform to what seemed to be the more consistent naming scheme.

      So in 0.4.1 it is just string to be consistent with bytes, chars, byteArray, etc... Pre 0.4.1 it is slurpString.

      Delete
  2. Why should we use "for" iteration ? not just

    out = output.outputProcessor.headOrTHMS.processor.asOutput
    out.write
    ...
    out.write

    ReplyDelete
  3. Good work! Servers as good lookup for me. One thing, I noticed is that you never close the file after reading/writing. Does it taken care of ? Thanks!

    ReplyDelete
  4. This works for me instead of the for comprehension:
    val o: Output = Resource.fromOutputStream(new FileOutputStream("/path/to/the/file"))
    o.outputProcessor.map(_.write("my name is methos").execute()).execute()

    ReplyDelete