scala inputstream io

¿Cuál es la forma correcta de codificar un ciclo de lectura en Scala?



inputstream io (3)

¿Cuál es el "correcto" de escribir el ciclo estándar de lectura en Scala? Por correcto me refiero a escrito de una manera similar a Scala en lugar de una forma similar a Java.

Aquí está el código que tengo en Java:

MessageDigest md = MessageDigest.getInstance( "MD5" ); InputStream input = new FileInputStream( "file" ); byte[] buffer = new byte[1024]; int readLen; while( ( readLen = input.read( buffer ) ) != -1 ) md.update( buffer, 0, readLen ); return md.digest();

Aquí está el código que tengo en Scala:

val md = MessageDigest.getInstance( hashInfo.algorithm ) val input = new FileInputStream( "file" ) val buffer = new Array[ Byte ]( 1024 ) var readLen = 0 while( readLen != -1 ) { readLen = input.read( buffer ) if( readLen != -1 ) md.update( buffer, 0, readLen ) } md.digest

El código de Scala es correcto y funciona, pero parece muy desagradable. Por un lado, es una traducción literal del código Java, sin aprovechar ninguna de las ventajas de Scala. Además, ¡en realidad es más largo que el código Java! Realmente siento que me estoy perdiendo algo, pero no puedo entender qué.

Soy bastante nuevo en Scala, y por eso estoy haciendo la pregunta para evitar caer en la trampa de escribir código de estilo Java en Scala. Estoy más interesado en la forma en Scala de resolver este tipo de problema que en cualquier método de ayuda específico que pueda proporcionar la API de Scala para codificar un archivo.

(Me disculpo por adelantado por mis adjetivos Scala ad hoc a lo largo de esta pregunta).


¿Qué pasa con una función al curry? Ustedes 11 líneas de código Scala se convierten en:

val md = MessageDigest.getInstance(hashInfo.algorithm) val input = new FileInputStream("file") iterateStream(input){ (data, length) => md.update(data, 0, length) } md.digest

La función iterateStream en la línea 3, que podría agregar a una biblioteca es:

def iterateStream(input: InputStream)(f: (Array[Byte], Int) => Unit){ val buffer = new Array[Byte](512) var curr = input.read(buffer) while(curr != -1){ f(buffer, curr) curr = input.read(buffer) } }

El código feo duplicado (donde se lee la entrada) termina en la biblioteca, bien probado y oculto para el programador. Siento que el primer bloque de código es menos complejo que la solución Iterator.continually .


Basado en el post de Rex que mencionó:

Stream.continually(input.read(buffer)).takeWhile(_ != -1).foreach(md.update(buffer, 0, _))

Debe reemplazar las líneas var readLen + mientras que {...} con ella, produce el mismo resultado.

Como mencionó Rex, funciona con scala 2.8.


Lo que Rex Kerr sugiere en su comentario es lo siguiente:

val md = MessageDigest.getInstance("MD5") val input = new FileInputStream("foo.txt") val buffer = new Array[ Byte ]( 1024 ) Stream.continually(input.read(buffer)) .takeWhile(_ != -1) .foreach(md.update(buffer, 0, _)) md.digest

La clave es el Stream.continually . Obtiene una expresión que se evalúa continuamente, creando un Stream infinito de la expresión evaluada. El takeWhile es la traducción de la condición while. El foreach es el cuerpo del while -loop.