Revisar un directorios.
No existe una clase oficial para revisar directorios en carpetas pero vamos a ver algunas alternativas.
Es muy simple escribir una función que recorra todas las carpetas y subcarpetas:
import java.io.File
def subdirs(dir: File): Iterator[File] = {
val children = dir.listFiles.filter(_.isDirectory)
children.toIterator ++ children.toIterator.flatMap(subdirs _)
}
Con esta función se puede visitar todos los subdirectorios:
for (d <- subdirs(dir)) process d
Si utilizamos Java 7, se puede utilizar el metodo walkFileTree de la clase java.nio.file.Files. Esta clase hace uso de la interfaz FileVisitor. En scala se prefiere utilizar funciones de objetos y no interfaces. Por lo tanto podemos adaptar esta funcionalidad a una visión más scala:
import java.nio.file._
implicit def makeFileVisitor(f: (Path) => Unit) = new SimpleFileVisitor[Path] {
override def visitFile(p: Path, attrs: attribute.BasicFileAttributes) = {
f(p)
FileVisitResult.CONTINUE
}
}
Por lo tanto se pueden imprimir todos los directorios de esta manera:
Files.walkFileTree(dir.toPath, (f: Path) => println(f))
Si se quiere realizar otra acción, se pasara otro método y no println
Serialización.
Esto no tiene ninguna relación con los cereales (jeje). En Java, la serialización es utilizada para cuando queremos transmitir un objeto a otra maquina virtual o para guardar el objeto por un tiempo mínimo.
En scala se puede utilizar el mismo mecanismo pero su declaración es un tanto diferente:
Java:
public class Person implements java.io.Serializable {
private static final long serialVersionUID = 42L;
…
}
Scala:
@SerialVersionUID(42L) class Person extends Serializable
El Trait Serializable esta definido en el paquete scala por lo que no es necesario ningún import.
Si nos olvidamos de @SerialVersionUID este tomara un valor por defecto.
Serializar y desserializar un objeto es similar a Java:
val fred = new Person(...)
import java.io._
val out = new ObjectOutputStream(new FileOutputStream("/tmp/test.obj"))
out.writeObject(fred)
out.close()
val in = new ObjectInputStream(new FileInputStream("/tmp/test.obj"))
val savedFred = in.readObject().asInstanceOf[Person]
En scala las colecciones son seriabilizables por lo que se pueden utilizar como atributos de objetos seriabilizables:
class Person extends Serializable {
private val friends = new ArrayBuffer[Person] // OK—ArrayBuffer is serializable
…
}
Procesos de control
Tradicionalmente los administradores de sistema utilizan un script de shell para hacer tareas de mantenimiento como mover archivos o combinarlos. Los lenguajes script hacen fáciles estas tareas pero como lenguajes de programación dejan mucho que desear.
Scala fue diseñado para poder hacer desde humildes script a grandes aplicaciones. El paquete scala.sys.process provee utilidades para interactuar con programas shell. Es decir que podemos escribir programas tipo shell con scala.
Veamos un ejemplo simple:
import sys.process._
"ls -al .." !
Como resultado obtendremos el listado de todos los archivos del directorio. sys.process tiene un convertidor implícito de string al objeto ProcessBuilder. Y con el operador ! ejecutamos el comando.
El resultado del operador ! es un numero entero que si es 0 el comando tuvo éxito y si es distinto de 0, no.
Si utilizamos el operador !! esto retornara un string :
val result = "ls -al .." !!
Se puede utilizar este resultado como entrada de otros programas con el operador |# que es similar al operador | de linux:
"ls -al .." #| "grep sec" !
Se puede redireccionar la salida con el operador #>
"ls -al .." #> new File("output.txt") !
Si se desea que se agregar en el archivo se puede utilizar #>>
"ls -al .." #>> new File("output.txt") !
Y si se desea introducir una estrada se debe utilizar #<
"grep sec" #< new File("output.txt") !
Se puede introducir un input desde una URL :
"grep Scala" #< new URL("http://horstmann.com/index.html") !
Notemos que los operadores de scala se diferencian de los operadores bash solo porque comienzan con el carácter #.