Esta es la clase controladora de la utilidad Concatenate:
import java.io.*;
class Concatenate {
public static void main(String[] args) {
ListOfFiles mylist = new ListOfFiles(args);
try {
SequenceInputStream s = new SequenceInputStream(mylist);
int c;
while ((c = s.read()) != -1) {
System.out.write(c);
}
s.close();
} catch (IOException e) {
System.err.println("Concatenate: " + e);
}
}
}
Lo primero que hace esta clase es crear un objeto ListOfFiles llamado mylist que es inicializado desde los argumentos de la línea de comandos introducidos por el usuario. Los argumentos de la línea de comandos son una lista de ficheros para ser concatendos. mylist es utilizada para inicializar el SequenceInputStream el cual utiliza mylist para obtener un nuevo InputStream para cada fichero listado por el usuario. ListOfFiles.java
import java.util.*;
import java.io.*;
class ListOfFiles implements Enumeration {
String[] listOfFiles;
int current = 0;
ListOfFiles(String[] listOfFiles) {
this.listOfFiles = listOfFiles;
}
public boolean hasMoreElements() {
if (current < listOfFiles.length)
return true;
else
return false;
}
public Object nextElement() {
InputStream is = null;
if (!hasMoreElements())
throw new NoSuchElementException("No more files.");
else {
try {
String nextElement = listOfFiles[current];
current++;
is = new FileInputStream(nextElement);
} catch (FileNotFoundException e) {
System.out.println("ListOfFiles: " + e);
}
}
return is;
}
}
ListOfFiles implementa el interface Enumeration.
Verás cómo esto entra en juego cuando pasemos por el resto del programa.
Después de que el método main() cree el SequenceInputStream, lo lee un byte cada vez. Cuando el SequenceInputStream necesite un InputStream para la nueva fuente (como para el primer byte leido o cuando se alcance el final del canal de entrada actual), llama a nextElement() en el objeto Enumeration para obtener el nuevo InputStream. ListOfFiles crea objetos FileInputStream perezosamente, lo que significa que si SequenceInputStream llama a nextElement(), ListOfFiles abre un FileInputStream con el siguiente fichero de la lista y devuelve el canal. Cuando el ListOfFiles alcanza el final de los ficheros (no hay más elementos), nextElement() devuelve nulo, y la llamada al método read() de SequenceInputStream devuelve -1 para indicar el final de la entrada.
La concatenación siplemente copia todos los datos leidos desde SequenceInputStream en la salida estandard.
Prueba esto: intenta concatenar los ficheros farrago.txt y words.txt que han sido utilizados como ficheros de entrada en esta lección.