I am using the asynchronous I/O library of the playframework which uses Iteratees and Enumerators. I now have an Iterator[T] as data sink (for simplification say it’s an Iterator[Byte] which stores its content into a file). This Iterator[Byte] is passed to the function which handles the writing.
But before writing I want to add some statistical information at the file begin (for simplification say it’s one Byte), so I transfer the iterator the following way before passing it to the write function:
def write(value: Byte, output: Iteratee[Byte]): Iteratee[Byte] =
Iteratee.flatten(output.feed(Input.El(value)))
When I now read the stored file from the disk, I get an Enumerator[Byte] for it.
At first I want to read and remove the additional data and then I want to pass the rest of the Enumerator[Byte] to a function which handles the reading.
So I also need to transform the enumerator:
def read(input: Enumerator[Byte]): (Byte, Enumerator[Byte]) = {
val firstEnumeratorEntry = ...
val remainingEnumerator = ...
(firstEnumeratorEntry, remainingEnumerator)
}
But I have no idea, how to do this. How can I read some bytes from an Enumerator and get the remaining Enumerator?
Replacing Iteratee[Byte] with OutputStream and Enumerator[Byte] with InputStream, this would be very easy:
def write(value: Byte, output: OutputStream) = {
output.write(value)
output
}
def read(input: InputStream) = (input.read,input)
But I need the asynchronous I/O of the play framework.
Here is one way to achieve this by folding within the
Iterateeand an appropriate (kind-of) State accumulator (a tuple here)I go read the
routesfile, the first byte will be read as aCharand the other will be appended to aStringas UTF-8 bytestrings.EDIT
I found yet another way using
Enumerateebut it needs to create 2Enumerators (one short lived). However is it a bit more elegant. We use a “kind-of” Enumeratee but theTraversalone which works at a finer level than Enumeratee (chunck level).We use
take1 that will take only 1 byte and then close the stream. On the other one, we usedropthat simply drops the first byte (because we’re using a Enumerator[Array[Byte]])Furthermore, now
read2has a signature much more closer than what you wished, because it returns 2 enumerators (not so far from Promise, Enumerator)