Java Flujos (Stream), Archivos (File) e IO
Los flujos (Stream), archivos (File) e IO (entrada/salida) en Java son la infraestructura para manejar la lectura y escritura de datos, y permiten que los programas interactúen con datos externos (como archivos, redes, entrada del sistema, etc.).
El paquete java.io es un paquete central en la biblioteca estándar de Java; proporciona clases para la entrada y salida del sistema, e incluye herramientas para manejar flujos de datos (flujos de bytes y de caracteres), lectura y escritura de archivos, serialización y formato de datos.
java.io es el paquete base para manejar operaciones de archivos, operaciones de flujos y operaciones de IO de bajo nivel.
Los flujos en el paquete java.io admiten muchos formatos, como: tipos primitivos, objetos, conjuntos de caracteres localizados, etc.
Un flujo puede entenderse como una secuencia de datos. Un flujo de entrada representa la lectura de datos desde un origen, y un flujo de salida representa la escritura de datos hacia un destino.
Lectura de entrada de consola
La entrada de consola en Java se realiza mediante System.in.
Para obtener un flujo de caracteres vinculado a la consola, puedes envolver System.in en un objeto BufferedReader para crear un flujo de caracteres.
La siguiente es la sintaxis básica para crear un BufferedReader:
Una vez creado el objeto BufferedReader, podemos usar el método read() para leer un carácter desde la consola, o el método readLine() para leer una cadena.
Leer entrada de múltiples caracteres desde la consola
Para leer un carácter de un objeto BufferedReader se utiliza el método read(), cuya sintaxis es la siguiente:
Cada vez que se llama al método read(), este lee un carácter del flujo de entrada y lo devuelve como un valor entero. Cuando el flujo llega a su fin, devuelve -1. Este método lanza IOException.
El siguiente programa demuestra el uso del método read() para leer caracteres desde la consola hasta que el usuario ingreseq。
Código del archivo BRRead.java:
El resultado de compilar y ejecutar el ejemplo anterior es el siguiente:
输入字符, 按下 'q' 键退出。 ejemplo r u n o o b q q
Leer cadenas desde la consola
Para leer una cadena desde la entrada estándar se necesita usar el método readLine() de BufferedReader.
Su formato general es:
El siguiente programa lee y muestra líneas de caracteres hasta que ingreses la palabra "end".
Código del archivo BRReadLines.java:
El resultado de compilar y ejecutar el ejemplo anterior es el siguiente:
Enter lines of text. Enter 'end' to quit. This is line one This is line one This is line two This is line two end end
En versiones posteriores a JDK 5 también podemos usarJava Scannerla clase para obtener la entrada de consola.
Salida de consola
Como se ha explicado anteriormente, la salida de consola se realiza con print() y println(). Estos métodos están definidos por la clase PrintStream, y System.out es una referencia a un objeto de esa clase.
PrintStream hereda de la clase OutputStream e implementa el método write(). De esta manera, write() también se puede usar para escribir en la consola.
El formato más simple de write() definido por PrintStream se muestra a continuación:
Este método escribe el byte de orden inferior de byteval en el flujo.
Ejemplo
El siguiente ejemplo usa write() para enviar a la pantalla el carácter 'A' y el salto de línea que le sigue:
Código del archivo WriteDemo.java:
Al ejecutar el ejemplo anterior, se muestra el carácter 'A' en la ventana de salida.
A
Nota:El método write() no se usa con frecuencia, porque los métodos print() y println() son más convenientes de usar.
Leer y escribir archivos
Como se mencionó anteriormente, un flujo se define como una secuencia de datos. El flujo de entrada se usa para leer datos de un origen, y el flujo de salida para escribir datos en un destino.
La siguiente imagen es un diagrama de jerarquía de clases que describe los flujos de entrada y salida.
Flujos de bytes (procesamiento de datos binarios)
Los flujos de bytes se utilizan para procesar datos binarios, como archivos, imágenes, videos, etc.
| Nombre de clase | Tipo | Descripción |
|---|---|---|
InputStream | Clase abstracta (flujo de entrada) | Superclase de todos los flujos de entrada de bytes; maneja operaciones de entrada de bytes. |
OutputStream | Clase abstracta (flujo de salida) | Superclase de todos los flujos de salida de bytes; maneja operaciones de salida de bytes. |
FileInputStream | Flujo de entrada | Lee datos de bytes de archivos. |
FileOutputStream | Flujo de salida | Escribe datos de bytes en archivos. |
BufferedInputStream | Flujo de entrada | Proporciona funcionalidad de buffer para los flujos de entrada de bytes, mejorando la eficiencia de lectura. |
BufferedOutputStream | Flujo de salida | Proporciona funcionalidad de buffer para los flujos de salida de bytes, mejorando la eficiencia de escritura. |
ByteArrayInputStream | Flujo de entrada | Utiliza un arreglo de bytes en memoria como origen de entrada. |
ByteArrayOutputStream | Flujo de salida | Escribe datos en un arreglo de bytes en memoria. |
DataInputStream | Flujo de entrada | Permite leer tipos de datos primitivos de Java desde el flujo de entrada (comoint、float、boolean)。 |
DataOutputStream | Flujo de salida | Permite escribir tipos de datos primitivos de Java en el flujo de salida. |
ObjectInputStream | Flujo de entrada | Lee objetos serializados desde el flujo de entrada. |
ObjectOutputStream | Flujo de salida | Serializa objetos y los escribe en el flujo de salida. |
PipedInputStream | Flujo de entrada | Se utiliza para leer datos de bytes en una tubería, normalmentePipedOutputStreamse usa en conjunto. |
PipedOutputStream | Flujo de salida | Se utiliza para escribir datos de bytes en una tubería, normalmentePipedInputStreamse usa en conjunto. |
FilterInputStream | Flujo de entrada | Clase envoltorio de los flujos de entrada de bytes, utilizada para filtrar otros flujos de entrada. |
FilterOutputStream | Flujo de salida | Clase envoltorio de los flujos de salida de bytes, utilizada para filtrar otros flujos de salida. |
SequenceInputStream | Flujo de entrada | Concatena varios flujos de entrada en uno solo para su procesamiento. |
Flujos de caracteres (procesamiento de datos de texto)
Los flujos de caracteres se utilizan para procesar datos de texto, como leer y escribir cadenas o archivos.
| Nombre de clase | Tipo | Descripción |
|---|---|---|
Reader | Clase abstracta (flujo de entrada) | Superclase de todos los flujos de entrada de caracteres; maneja operaciones de entrada de caracteres. |
Writer | Clase abstracta (flujo de salida) | Superclase de todos los flujos de salida de caracteres; maneja operaciones de salida de caracteres. |
FileReader | Flujo de entrada | Lee datos de caracteres de archivos. |
FileWriter | Flujo de salida | Escribe datos de caracteres en archivos. |
BufferedReader | Flujo de entrada | Proporciona funcionalidad de buffer para los flujos de entrada de caracteres, admite lectura por líneas y mejora la eficiencia de lectura. |
BufferedWriter | Flujo de salida | Proporciona funcionalidad de buffer para los flujos de salida de caracteres, admite escritura por líneas y mejora la eficiencia de escritura. |
CharArrayReader | Flujo de entrada | Utiliza un arreglo de caracteres como origen de entrada. |
CharArrayWriter | Flujo de salida | Escribe datos en un arreglo de caracteres. |
StringReader | Flujo de entrada | Utiliza una cadena como origen de entrada. |
StringWriter | Flujo de salida | Escribe datos en un búfer de cadena. |
PrintWriter | Flujo de salida | Flujo de salida de caracteres conveniente, compatible con actualización automática y salida formateada. |
PipedReader | Flujo de entrada | Se utiliza para leer datos de caracteres en una tubería, generalmente conPipedWriterusarse en combinación. |
PipedWriter | Flujo de salida | Se utiliza para escribir datos de caracteres en una tubería, generalmente conPipedReaderusarse en combinación. |
LineNumberReader | Flujo de entrada | Flujo de entrada de caracteres con búfer y números de línea, que permite realizar un seguimiento del número de línea leído. |
PushbackReader | Flujo de entrada | Permite devolver caracteres al flujo después de leerlos, para poder leerlos nuevamente. |
Clases auxiliares (otras clases importantes)
Las clases auxiliares brindan soporte para archivos, directorios y acceso a archivos aleatorios.
| Nombre de clase | Tipo | Descripción |
|---|---|---|
File | Operaciones de archivos y directorios | Se utiliza para representar un archivo o directorio, y proporciona operaciones de archivo como crear, eliminar, renombrar, etc. |
RandomAccessFile | Archivo de acceso aleatorio | Admite acceso aleatorio a archivos; se pueden leer y escribir datos desde cualquier posición del archivo. |
Console | Entrada y salida de consola | Proporciona soporte de entrada y salida para la consola del sistema. |
Los dos flujos importantes que se discutirán a continuación sonFileInputStreamyFileOutputStream。
FileInputStream
Este flujo se utiliza para leer datos de un archivo; su objeto se puede crear con la palabra clave new.
Hay varios métodos de construcción que se pueden usar para crear objetos.
Se puede usar un nombre de archivo de tipo cadena para crear un objeto de flujo de entrada y leer el archivo:
También se puede usar un objeto File para crear un objeto de flujo de entrada y leer el archivo. Primero debemos usar el método File() para crear un objeto File:
Una vez creado el objeto InputStream, se pueden usar los siguientes métodos para leer el flujo o realizar otras operaciones de flujo.
| Método | Descripción | Código de ejemplo |
|---|---|---|
int read() | Lee un byte de datos y devuelve un entero entre 0 y 255. Si se llega al final del flujo, devuelve -1. | int data = inputStream.read(); |
int read(byte[] b) | Lee bytes del flujo de entrada y los almacena en la matriz de bytesby devuelve el número real de bytes leídos. Si se llega al final del flujo, devuelve -1. | byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer); |
int read(byte[] b, int off, int len) | Lee como máximolenbytes del flujo de entrada y los almacena en la matriz de bytesbdeoffen la posición de desplazamiento, y devuelve el número real de bytes leídos. Si se llega al final del flujo, devuelve -1. | byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer, 0, buffer.length); |
long skip(long n) | Omite y descartanbytes del flujo de entrada y devuelve el número real de bytes omitidos. | long skippedBytes = inputStream.skip(100); |
int available() | Devuelve el número de bytes que se pueden leer (sin bloquear). | int availableBytes = inputStream.available(); |
void close() | Cierra el flujo de entrada y libera todos los recursos asociados con él. | inputStream.close(); |
void mark(int readlimit) | Establece una marca en la posición actual del flujo;readlimites el límite superior de bytes que se pueden leer. | inputStream.mark(1024); |
void reset() | Reposiciona el flujo en la última posición marcada; si no hay marca o esta no es válida, lanzaIOException。 | inputStream.reset(); |
boolean markSupported() | Comprueba si el flujo de entrada actual admitemark()yreset()la operación. | boolean isMarkSupported = inputStream.markSupported(); |
Además de InputStream, hay otros flujos de entrada. Para más detalles, consulte el siguiente enlace:
FileOutputStream
Esta clase se utiliza para crear un archivo y escribir datos en él.
Si el archivo de destino no existe antes de que el flujo abra el archivo para salida, el flujo creará el archivo.
Hay dos métodos de construcción que se pueden usar para crear objetos FileOutputStream.
Use un nombre de archivo de tipo cadena para crear un objeto de flujo de salida:
También se puede usar un objeto File para crear un flujo de salida y escribir en el archivo. Primero debemos usar el método File() para crear un objeto File:
Una vez creado el objeto OutputStream, se pueden usar los siguientes métodos para escribir en el flujo o realizar otras operaciones de flujo.
| Método | Descripción | Código de ejemplo |
|---|---|---|
void write(int b) | Escribe el byte especificado en el flujo de salida;bsus 8 bits más bajos se escribirán en el flujo. | outputStream.write(255); |
void write(byte[] b) | Escribe todos los bytes de la matriz de bytesben el flujo de salida. | byte[] data = "Hello".getBytes(); outputStream.write(data); |
void write(byte[] b, int off, int len) | De la matriz de bytes,bdesde el desplazamientooffespecificado,lenescribe bytes en el flujo de salida. | byte[] data = "Hello".getBytes(); outputStream.write(data, 0, data.length); |
void flush() | Vacía el flujo de salida y fuerza la escritura de todos los datos almacenados en el búfer, asegurando que los datos se escriban inmediatamente en el destino de salida. | outputStream.flush(); |
void close() | Cierra el flujo de salida y libera todos los recursos asociados con él. Después de cerrarlo, no se puede escribir. | outputStream.close(); |
Además de OutputStream, hay otros flujos de salida. Para más detalles, consulte el siguiente enlace:
Ejemplo
A continuación se muestra un ejemplo que demuestra el uso de InputStream y OutputStream:
Código del archivo fileStreamTest.java:
El programa anterior primero crea el archivo test.txt, escribe los números dados en el archivo en forma binaria y, al mismo tiempo, los muestra en la consola.
El código anterior, al ser una escritura binaria, puede contener caracteres ilegibles. Puede usar el siguiente ejemplo de código para resolver el problema de los caracteres ilegibles:
Código del archivo fileStreamTest2.java:
Archivos e I/O
También hay algunas clases sobre archivos y E/S que debemos conocer:
Directorios en Java
Crear directorios:
En la clase File hay dos métodos que se pueden usar para crear carpetas:
- mkdir( )El método crea una carpeta; si tiene éxito, devuelve true; si falla, devuelve false. El fallo indica que la ruta especificada por el objeto File ya existe, o que la carpeta no se puede crear porque la ruta completa aún no existe.
- mkdirs()El método crea una carpeta y todas sus carpetas padre.
El siguiente ejemplo crea la carpeta "/tmp/user/java/bin":
Código del archivo CreateDir.java:
Compile y ejecute el código anterior para crear el directorio "/tmp/user/java/bin".
Nota:Java distingue automáticamente los separadores de ruta de archivo según la convención en UNIX y Windows. Si usa el separador (/) en la versión de Java para Windows, la ruta aún se puede analizar correctamente.
Leer directorios
Un directorio es en realidad un objeto File que contiene otros archivos y carpetas.
Si se crea un objeto File y este es un directorio, al llamar al método isDirectory() devolverá true.
Se puede extraer la lista de archivos y carpetas que contiene llamando al método list() de ese objeto.
El siguiente ejemplo muestra cómo usar el método list() para verificar el contenido de una carpeta:
Código del archivo DirList.java:
El resultado de compilar y ejecutar el ejemplo anterior es el siguiente:
目录 /tmp bin 是一个目录 lib 是一个目录 demo 是一个目录 test.txt 是一个文件 README 是一个文件 index.html 是一个文件 include 是一个目录
Eliminar directorios o archivos
Para eliminar archivos se puede usarjava.io.File.delete()el método.
El siguiente código eliminará el directorio/tmp/java/. Tenga en cuenta que al eliminar un directorio, debe asegurarse de que no haya otros archivos en ese directorio para poder eliminarlo correctamente; de lo contrario, la eliminación fallará.
Estructura del directorio de prueba:
/tmp/java/ |-- 1.log |-- test
