Skip to content

Instantly share code, notes, and snippets.

@spiechu
Last active January 2, 2016 07:39
Show Gist options
  • Save spiechu/8271212 to your computer and use it in GitHub Desktop.
Save spiechu/8271212 to your computer and use it in GitHub Desktop.
My first sloppy steps into Scala. Check corresponding blog post at http://spiechu.pl/2014/01/05/computing-file-hashes-using-scala
// Typical Java package declaration.
package pl.spiechu.hashutils
// Typical class imports. More than one in curly brackets.
// Java classes work just fine in Scala.
import java.io.{ File, FileInputStream }
import java.security.MessageDigest
/**
* Singleton object. You cannot create an instance using 'new'.
* Construct built-in into language.
*
* @author Dawid Spiechowicz (spiechu@gmail.com)
*/
object HashGenerator {
// We're inside constructor body.
/**
* Input stream buffer size.
*
* Final val is constant expression.
*/
final val BUFFER_SIZE = 8192
/**
* Hash algorithm type.
*/
final val HASH_TYPE = "SHA-256"
// Val ensures me that no one will reassign something to that.
// Think about it as 'final' Java keyword.
// Notice no empty bracket after name in array type.
val buffer = new Array[Byte](BUFFER_SIZE)
// You can leave off most of dots.
val shaDigest = MessageDigest getInstance (HASH_TYPE)
/**
* You don't need to provide return type,
* but you should because of public API clarity.
*/
def getSha1HashUsingFuncChain(file: File): String = {
// You can leave off parentheses in no arg functions.
shaDigest reset
val fis = new FileInputStream(file)
// Infinite looping until read() result equals -1,
// until that happens run foreach().
Stream
.continually(fis read (buffer))
.takeWhile(_ != -1)
.foreach(shaDigest update (buffer, 0, _))
// Last expression in function is always returned.
getHashString
}
/**
* Works fine without return type provided.
*/
def getSha1HashUsingMatcher(file: File) = {
shaDigest reset
val fis = new FileInputStream(file)
// Define inner function that can be called recurrently.
// Recursive method needs a return type. Think of 'Unit' as void.
def readStream(): Unit = {
// read() result intercepted by matcher.
fis.read(buffer) match {
case -1 => ()
// Do digest update job and call recurrent.
// Notice that readStream call is the last,
// so compiler can perform tail recursion optimization.
case num => shaDigest update (buffer, 0, num); readStream
}
}
// Launch first iteration.
readStream
getHashString
}
/**
* Default 'def' refers to 'public' access, You can narrow it.
*/
protected def getHashString() = {
val hexbuilder = new StringBuilder
// Iterate over byte array and cut off everything beside one byte.
// Eclipse complains about implicit conversion to 'byteArrayOps',
// stay tuned for the next blog post at spiechu.pl explaining this.
shaDigest.digest.foreach(bt => hexbuilder append (Integer toHexString (0xFF & bt)))
hexbuilder toString
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment