Scala: Píšeme Iterator wrapper pro InputStream
V tomto článku si ukážeme, jak napsat Iterator wrapper pro InputStream.
Wrappery budou celkem dva. První, který bude data načítat po bytech, a druhý, který je bude načítat pomocí bufferu. Každý z wrapperů bude dědit z traitu Iterator, kde je potřeba implementovat metody next() a hasNext().
Nejdříve si ukážeme celý kód včetně objektu pro jejich vyzkoušení:
import java.io._ class ISWrapper(is: InputStream) extends Iterator[Int] { var value = 0 def next = value def hasNext = { value = is.read value != -1 } } class ISBufferedWrapper(is: InputStream, size: Int) extends Iterator[Array[Byte]] { var value: Array[Byte] = null def next = value def hasNext = { val b = new Array[Byte](size) val read = is.read(b); value = b take read read > 0 } } object wrapperTest extends Application { val isw = new ISWrapper(new FileInputStream("file")) println("ISWrapper:") for(ch <- isw) print(ch.toChar) println("\n") println("ISBufferedWrapper:") val isbw = new ISBufferedWrapper(new FileInputStream("file"),1000) for(ch <- isbw) ch foreach { ch2 => print(ch2.toChar) } println() }
Poznámky ke kódu
U prvního wrapperu chceme, aby metoda next() vracela celočíselnou hodnotu. Proto při dědění z traitu Iterator specifikujeme genericky typ jako Int. Analogicky platí totéž pro druhý wrapper – next() bude vracet Array[Byte]:
class ISWrapper(is: InputStream) extends Iterator[Int] { . . class ISBufferedWrapper(is: InputStream, size: Int) extends Iterator[Array[Byte]] {
Metoda hasNext() je volána vždy před přečtením dalšího bytu/pole bytů. Proto při jejím volání již dané data načteme, jejich hodnotu uložíme a rozhodneme, jestli se nacházíme na konci streamu. Při volání metody next() už jenom vrátíme uloženou hodnotu.
def hasNext = { value = is.read value != -1 } . . def hasNext = { val b = new Array[Byte](size) val read = is.read(b); value = b take read read > 0 }