In an attempt to begin learning Scala, I've taken a stab at creating a simple wrapper around Java's File & FileInputStream in order to read lines from a file. This functionality already exists in the Source class and is just a learning exercise.
If you were building this wrapper in Scala, is there anything you might change? Are there any best practices I'm overlooking?
////////// Driver.scala ////////////////
object Driver {
def main(args: Array[String]): Unit = {
val uri = File.classpathResource("sample.txt")
val fileReader = FileReader.open(uri)
println("Reading File: " + fileReader.file.name() )
for( val line <- fileReader.lines() ) {
println(line)
}
fileReader.close()
}
}
////////// File.scala ////////////////
import java.io.{File => JavaFile}
import java.net.URI
/** This object provides convenience methods for working with local file resources */
object File {
/** Helper method to resolve a URI for a resource on the classpath
*
* @param the resource's path name
* @return the resource's URI
*/
def classpathResource(pathName: String): URI = {
val url = this.getClass().getClassLoader().getResource(pathName)
url.toURI()
}
}
/** This class represents a file on the file system */
class File(val javaFile: JavaFile) {
def this(pathName: String) = this(new JavaFile(pathName))
def this(uri: URI) = this(new JavaFile(uri))
/** Get the file's file name */
def name(): String = javaFile.getName()
/** Get the file's absolute path */
def path(): String = javaFile.getAbsolutePath()
/** Open a new file reader. Call FileReader.close() once you have finished
* using the file reader.
*
* @return a new file reader instance
* @throws FileNotFoundException if the file cannot be opened for reading
*/
def openReader(): FileReader = {
new FileReader(this)
}
}
////////// FileReader.scala ////////////////
import java.io.FileInputStream
import java.net.URI
/** This object provides convenience methods for reading files */
object FileReader {
/** Creates and opens a FileReader class instance for a given file's path name
*
* @param the file's path name
* @return an instance of the File class
* @throws FileNotFoundException if the file cannot be opened for reading
*/
def open(pathName: String): FileReader = this open new File(pathName)
/** Creates and opens a FileReader class instance for a given file's URI
*
* @param the file's URI
* @return an instance of the File class
* @throws FileNotFoundException if the file cannot be opened for reading
*/
def open(uri: URI): FileReader = this open new File(uri)
/** Creates and opens a FileReader class instance for a given File instance
*
* @param a File instance
* @return an instance of the FileReader class
* @throws FileNotFoundException if the file cannot be opened for reading
*/
def open(file: File): FileReader = new FileReader(file)
}
class FileReader(val file: File) {
private val inputStream = new FileInputStream(file.javaFile)
private val lineIterator = new BufferedLineIterator(inputStream);
/** Read the file's lines using a string iterator
*
* @return file's line iterator (Iterator[String])
*/
def lines(): Iterator[String] = lineIterator
/** Closes the file reader */
def close(): Unit = inputStream.close()
}
////////// BufferedLineIterator.scala ////////////////
import scala.collection.Iterator
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.InputStream
class BufferedLineIterator(inputStream: InputStream) extends Iterator[String] {
/** Buffered reader for reading lines from the file */
private val bufferedReader: BufferedReader = {
val inputStreamReader = new InputStreamReader(inputStream)
new BufferedReader(inputStreamReader)
}
/** Stores the next line waiting to be returned from the next() method */
private var nextLine: String = null
/** Identifies if the file has another line to read
*
* @return boolean identifying if the file has another line to read
*/
override def hasNext(): Boolean = {
if( nextLine == null ) {
nextLine = bufferedReader.readLine
}
nextLine != null
}
/** Reads the next line from the file
*
* @return the line
*/
override def next(): String = {
try {
if(hasNext) {
nextLine
} else {
Iterator.empty.next
}
} finally {
nextLine = null
}
}
}
valthere. In 2.10 it's use is forbidden. ;) – sschaef Sep 10 '12 at 8:45