G.Bordel >Docencia >TAP | Técnicas Actuales de Programación | (curso 2010-2011) | |||||||
|
|||||||||
tema_anterior | Tema 9: Entrada y salida de datos | tema_siguiente |
|
9.2- Estructura de clases para E/S
Dentro de java.io
encontramos algunas clases de interés además de todas aquellas que conforman el núcleo básico de lo que es entrada/salida en Java. Nos centraremos en primer lugar en este núcleo básico y dejaremos par el final las otras clases.
El mencionado núcleo básico está formado por cuatro árboles de clases que podemos representar gráficamente como en la siguiente figura, ordenados según dos criterios: por un lado entrada-salida y por otro byte-caracter, de modo que los cuatro árboles se corresponden con las 4 combinaciones posible de estos dos elementos: entrada de bytes, entrada de caracteres, salida de bytes y salida de caracteres.
La diferenciación entre bytes y caracteres viene forzada por el hecho de que los caracteres en Java se codifican en UNICODE, por lo que son elementos de 16 bits (si fuesen de 8 bits podria reducirse todo a entrada y salida de bytes y su adecuada interpretación como caracteres en el caso necesario).
![]() Las clases que tratan con "streams" se agrupan en cuatro árboles y dentro de cada uno hay dos tipos de funcionalidades: conexión con origenes y destinos y procesammientos (la representación gráfica no refleja relaciones de herencia reales). |
Cada uno de estos árboles, a su vez, puede considerarse compuesto por dos tipos de clases, relacionadas unas con origenes o destinos de datos, y otras con tipos de procesamiento. De este modo se separan las funcionalidades de los origenes y destinos pudiendose combinar unas con otros. Las clases con capacidad de procesamiento son "wrappers" (envoltorios, un patrón de diseño software) que se aplican a las clases de origen o destino proporcionando sus capacidades al origen o destino que envuelven (se verán ejemplos más adelante).
|
A la izquierda vemos los 4 árboles en donde, con fondo gris se encuentran las clases ligadas a fuentes y destinos de datos y con fondo blanco las clases que realizan algúnu tipo de procesamiento. Todas ellas se comentarán más adelante. Prestaremos atención en este momento a las cuatro clases raíz de los árboles.
Estas clases proporcionan el método básico para entrada (
Además de estos métodos básicos, se dispone de lectura y escritura de bloques sobre arrays:
Por último un tercer tipo de método permite leer o escribir dentro de una zona de un array: A continuación veremos la funcionalidad de cada una de las clases que contienen estos cuatro árboles, pero comenzamos por ver cómo hay una regularidad en la denominación de las clases que nos facilita su memorización: todas las clases que tratan con bytes se "adueñan" del término "stream" denominandose XxxInputStream o XxxOutputStream dependiendo de que sean de entrada o de salida, donde Xxx representa bien la denominación del origen o destino de datos o bien su funcionalidad; por otro lado las clases que tratan con caracteres se denominan XxxReader o XxxWriter en función de que sean de entrada o de salida y del mismo modo y coincidiendo con el otro caso, Xxx es la denominación del origen o destino de los datos. |
En la siguiente tabla pueden verse las clases de entrada y salida de los origenes y destinos básicos. Estos orígenes y destinos son de tres tipos: estructuras de memoria, "pipes" (tuberias entre procesos) y ficheros. Tanto en el caso de pipes como de ficheros, la regularidad es total disponiendo de las 4 clases necesarias (Reader,Writer,InputStream y OutpuStream). Por el contrario en el caso de la memoria existen diferencias. Las Strings pueden ser leidas y escritas mediante caracteres, y existe una clase para leer StringBuffers como bytes pero no debe ser utilizada (se mantiene para seguir soportando antiguos programas que la utilizaran). Además de esto se puede acceder a array tanto en lectura como en escritura con la particularidad ievidente de que los streams actuarán sobre ByteArray y los Reader y Writer sobre CharArray.
![]() Clases de entrada y salida de los origenes y destinos básicos. |
En el caso de las clases que procesan datos las regularidades son menores. A continuación vemos la tabla y comentaremos las particularidades que procedan en cada caso
![]() Clases para entradas y salidas con procesamiento de datos. |
InputStreamReader
y OutputStreamReader
. Disponemos de un ejemplo muy simple con la entrada estándar: si no ha sido redireccionada sabemos que se refiere al teclado y por tanto recoge caracteres, y sin embargo el objeto que se nos proporciona -System.in
- es un InputStreamReader
(para no limitar las posibilidades de redireccionamiento), de modo que normalmente envolveremos a este objeto para convertirlo en un Reader.
|
readLine()
). De nuevo podemos fijarnos en la entrada estándar:
|
|
SequenceInputStream
permite leer bytes de una serie de fuentes como si se tratase de una sola, encargandose de cerrar una y abrir la siguiente cuando es preciso. (esta necesidad aplicada al caso de caracteres en lugar de bytes justifica también la necesidad de las clases de conexión entre bytes y caracteres como se ve en el siguiente ejemplo).
|
DataInputStream
y DataOutputStream
proporcionan métodos para leer y escribir toda clase de elementos primitivos como tal, es decir en modo binario (no textual).
LineNumberInputStream
- ha dejado de ser de utilidad desde que apareció la de caracteres -LineNumberReader
- (los streams existen desde el primer momento, la versión 1.0, mientras que Readers y Writers aparecieron en la 1.1).
print
y println
admitiendo como parámetros todos los tipos de datos primitivos y objetos. Un objeto de este tipo ya es conocido para nosotros: el System.out
que utilizabamos en el programa "HolaMundo" es un PrintStream
.
File
Esta clase representa a los ficheros del sistema, tanto archivos como directorios, y proporciona métodos para realizar operaciones relativas al sistema de ficheros (crear directorios, determinar las raices, etc). Un objeto de esta clase será una representación de una entrada en el sistema de ficheros y permite obtener información referente a ella (tamaño, fecha de creación, etc) y determinar su situación (path canónico, prefijo, absoluto) y en todo caso con independencia de las particularidades del sistema operativo (distintos separadores).
StreamTokenizer
Esta clase es, en principio, similar a la ya conocida StringTokenizer
con la diferencia de que en este caso el objeto a trocear es cualquier clase de Stream de entrada. Esta funcionalidad similar esta ampliada con la capacidad específica de reconocer elementos propios de los lenguajesde programación como identificadores, números y comentarios.
RandomAccessFile
Esta clase permite la entrada y salida de datos frente a un fichero de un modo que podemos considerar no secuencial, ya que al disponer del método seek
que permite situarse en un punto cualquiera del mismo, pueden hacerse accesos aleatorios. La clase dispone de métodos de lectura y escritura de todos los métodos primitivos.
Siguiente punto: 9.3- E/S de objetos. Serialización
Plataforma de soporte a curso y contenidos (c) German Bordel 2005. |