Skip to content

Commit

Permalink
Added Io.readBytesFromResources() to read binary data. (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
tfenne authored Aug 6, 2018
1 parent ac9e9aa commit 98c38b0
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 10 deletions.
38 changes: 28 additions & 10 deletions src/main/scala/com/fulcrumgenomics/commons/io/Io.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import java.io._
import java.nio.file.{Files, Path}

import com.fulcrumgenomics.commons.CommonsDef._

import scala.io.Source

/**
Expand Down Expand Up @@ -181,6 +182,13 @@ trait IoUtil {
/** Creates an object that will asynchronously read character data from a stream and pipe it into a sink function. */
def pipeStream(stream: InputStream, sink: String => Unit) : AsyncStreamSink = new AsyncStreamSink(stream, sink)

/** Private function to get an input stream from a resource, or fail if the resource doesn't exist. */
private def streamFromResource(name: String): InputStream = {
Seq(getClass.getResourceAsStream _, getClass.getClassLoader.getResourceAsStream _)
.flatMap(m => Option(m(name)))
.headOption.getOrElse(throw new IllegalArgumentException(s"Resource does not exist at path: $name"))
}

/** Finds a resource with a given name on the classpath and produces an iterator of lines of text from the resource.
*
* The way resources are traditionally loaded from the class path via `Class.getResource()` and
Expand All @@ -191,17 +199,27 @@ trait IoUtil {
*
* The implementation here first tries `Class.getResource` and then `ClassLoader.getResource` to enable it to
* find relative paths and also absolute paths with and without leading `/s`.
*
*/
def readLinesFromResource(name: String): Iterator[String] = {
Seq(getClass.getResourceAsStream _, getClass.getClassLoader.getResourceAsStream _)
.flatMap(m => Option(m(name)))
.headOption match {
case None =>
throw new IllegalArgumentException(s"Resource does not exist at path: $name")
case Some(in) =>
val stream = new BufferedInputStream(in, bufferSize)
Source.fromInputStream(stream).withClose(() => stream.safelyClose()).getLines
}
val stream = new BufferedInputStream(streamFromResource(name), bufferSize)
Source.fromInputStream(stream).withClose(() => stream.safelyClose()).getLines
}

/** Finds a resource with a given name on the classpath and produces an array of the bytes from the resource.
*
* The way resources are traditionally loaded from the class path via `Class.getResource()` and
* `ClassLoader.getResource()` have confusing behaviour. Notably:
*
* * Class.getResource() interprets paths as relative, and requires a leading `/` to make them absolute
* * ClassLoader.getResource() interprets all paths a absolute and fails on leading `/`s
*
* The implementation here first tries `Class.getResource` and then `ClassLoader.getResource` to enable it to
* find relative paths and also absolute paths with and without leading `/s`.
*/
def readBytesFromResource(name: String): Array[Byte] = {
val stream = new BufferedInputStream(streamFromResource(name), bufferSize)
val array = Iterator.continually(stream.read()).takeWhile(_ != -1).map(_.toByte).toArray
stream.safelyClose()
array
}
}
Binary file not shown.
7 changes: 7 additions & 0 deletions src/test/scala/com/fulcrumgenomics/commons/io/IoTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
package com.fulcrumgenomics.commons.io

import java.io.{BufferedOutputStream, FileOutputStream}
import java.nio.file.{Files, Path, Paths}

import com.fulcrumgenomics.commons.util.UnitSpec
Expand Down Expand Up @@ -186,4 +187,10 @@ class IoTest extends UnitSpec {
it should "fail when the resource does not exist" in {
an[IllegalArgumentException] should be thrownBy Io.readLinesFromResource("/path/does/not/exist.json")
}

"Io.readBytesFromResource" should "correctly read binary data from a resource" in {
val expected = Range.inclusive(Byte.MinValue, Byte.MaxValue).map(_.toByte).toArray
val actual = Io.readBytesFromResource("/com/fulcrumgenomics/commons/io/to-bytes-from-resource-test.bin")
actual shouldBe expected
}
}

0 comments on commit 98c38b0

Please sign in to comment.