Hasta ahora los programas realizados consisten en explotar el uso de memoria volátil para manejar datos, una vez finaliza un programa éstos datos se pierden. Sin embargo, es posible crear aplicaciones que puedan manejar datos que se guarden en archivos dentro de un disco duro, que sean persistentes.
Java, así como otros lenguajes, posee una serie de librerías para manipular archivos, con las operaciones comunes, como ser: creación, edición y eliminación de archivos. Además es posible manipular el contenido interior de cada archivo ya sea leyendo datos o escribiendo datos en el archivo.
1- Archivo
Un archivo es un conjunto de bits almacenados en un dispositivo, y accesible a través de un camino de acceso que lo identifica.
1.1- Contenido de un Archivo
Hay dos formas de visualizar el contenido de un archivo:
- Archivos de caracteres o de texto: El cual es formado por medio de caracteres y puede ser visto y editado en un editor de texto (Por ejemplo: Notepad). Un ejemplo de un archivo de texto es el código fuente de un archivo Java.
- Archivos de bytes o binarios: Formado por los bytes. Este tipo de archivos puede representar casi cualquier cosa, por ejemplo: imágenes, audio, video, documentos especiales como los de Microsoft Office.
1.2- Modo de Acceso de un Archivo
- Secuencial: información del archivo es una secuencia de bytes (o caracteres) de manera que para acceder a un byte o carácter en particular es necesario acceder a los bytes previos.
- Acceso directo (aleatorio): Nos permite acceder directamente a un byte en particular
2- Package java.io y java.nio
Java tiene dos packages para la manipulación de archivos: java.io y java.nio. El primero se introdujo en el JDK 1.4, mientras que el segundo fue en el JDK 7. La diferencia más grande entre las dos librerías consiste en lo siguiente:
java.io | java.nio |
---|---|
Orientado a flujo (stream) | Orientado a búfer |
Bloqueo de E/S | No hay bloqueo de E/S |
Selectores |
2.1- Orientado a Flujo (stream) vs Orientado a Búfer
Java IO está orientado al flujo significa que lee uno o más bytes a la vez. No se almacenan en caché en ninguna parte. Además, no puede avanzar y retroceder en los datos en una secuencia. Si necesita avanzar y retroceder en los datos leídos de una secuencia, primero deberá almacenarlos en un búfer.
En NIO se trabaja con canales y búfer. Los datos se escriben de un búfer hacia un canal, y son leídos de un canal hacia un buffer. Los datos se leen en un búfer desde el que luego se procesan. Puede moverse hacia adelante y hacia atrás en el búfer según lo necesite. Esto le brinda un poco más de flexibilidad durante el procesamiento. Sin embargo, también debe verificar si el búfer contiene todos los datos que necesita para procesarlo por completo. Y, debe asegurarse de que al leer más datos en el búfer, no sobrescriba los datos en el búfer que aún no ha procesado.
2.2- Bloqueo de E/S vs No Bloqueo de E/S
Los flujos de Java IO bloquean. Eso significa que cuando un hilo de ejecución invoca la lectura o escritura de un archivo, ese hilo se bloquea hasta que haya algunos datos para leer, o los datos estén completamente escritos. El hilo no puede hacer nada más mientras tanto.
El modo sin bloqueo de Java NIO permite que un hilo solicite datos de lectura de un canal y solo obtenga lo que está disponible actualmente; o nada en absoluto, si no hay datos disponibles actualmente. En lugar de permanecer bloqueado hasta que los datos estén disponibles para leer, el hilo puede continuar con otra cosa.
Lo mismo es cierto para la escritura sin bloqueo. Un sub-proceso puede solicitar que se escriban algunos datos en un canal, pero no esperar a que se escriban completamente. El hilo puede continuar y hacer otra cosa mientras tanto.
Mientras tanto, en qué sub-procesos pasan su tiempo inactivo cuando no están bloqueados en las llamadas IO, generalmente se realiza IO en otros canales. Es decir, un solo hilo ahora puede gestionar múltiples canales de entrada y salida.
2.3- Selectores
Java NIO provee el concepto de selectores. Los selectores permiten que un solo hilo monitoree múltiples canales de entrada para eventos como que los datos han llegado, la conexion ha sido abierta, etc. Puede registrar múltiples canales con un selector, luego usar un solo hilo para «seleccionar» los canales que tienen entrada disponible para el procesamiento, o seleccionar los canales que están listos para escribir. Este mecanismo de selección facilita que un solo hilo administre múltiples canales.
3- Clases importantes
3.1- java.nio.files.Path
Un objeto que puede usarse para ubicar un archivo en un sistema de archivos. Normalmente representará una ruta de archivo dependiente del sistema. Posee una serie de funciones útiles para manejar ubicaciones.
Entre las funciones de estos objetos se tiene:
- endsWith
- getFileName
- getFileSystem
- getParent
- getRoot
- isAbsolute
- startsWith
- toAbsolutePath
- toFile
- toString
- toUri
3.2- java.nio.files.Paths
Esta clase permite que a partir de un String se obtenga un objeto de tipo Path. Esto se realiza con el método get()
3.3- java.nio.files.Files
Esta clase posee funciones static para operar archivos, directorios. En la mayoría de los casos, los métodos definidos delegarán al proveedor del sistema de archivos asociado para realizar las operaciones de archivo.
Entre las funciones que se tienen están:
- copy
- createDirectories
- delete
- deleteIfExists
- exists
- isHidden
- isReadable
- isSameFile
- isWritable
- move
- readAllBytes
- readAllLines
- size
- write
3.4- java.io.IOException
En el manejo de archivos es posible obtener una excepción del tipo IOException, para lo cual es necesario establecer en las cabeceras de las funciones o en los bloques try/catch este tipo de objetos.
Bibliografía
[1] https://dzone.com/articles/java-nio-vs-io
[2] https://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html
[3] https://docs.oracle.com/javase/7/docs/api/java/nio/file/Paths.html
[4] https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html
[5] https://docs.oracle.com/javase/7/docs/api/java/io/IOException.html