Cómo se creó el archivo
Primero observe el constructor de la clase File y concluya que hay tres formas comunes de crear
Pase directamente la ruta del archivo construido, a través del constructor File(String pathname), pase directamente la ruta del archivo, el siguiente es el código de demostración (la operación del flujo IO siempre va acompañada de una excepción en tiempo de compilación, puede usar la excepción de tecla de método abreviado Alt+Intro detectada o lanzada)
public void create01() {
String filePath = "d:\\IOTest\\test1.txt";
File file = new File(filePath);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
Especifique el archivo de directorio principal, es decir, el archivo de carpeta especificado + el archivo de subruta, y cree el archivo a través del constructor Archivo (Archivo principal, Cadena secundaria)
public void create02() {
File parentFile = new File("d:\\IOTest");
String fileName = "test2.txt";
File file = new File(parentFile, fileName);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
Especifique directamente el directorio principal y el nombre del archivo, a través del constructor Archivo (String parent, String child)
public void create03() {
String parentPath = "d:\\IOTest";
String fileName = "test3.txt";
File file = new File(parentPath, fileName);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
Operaciones comunes de archivos
ver información del archivo
El documento api de la clase de archivo File, desde el cual podemos ver que la clase File proporciona muchas API para que podamos ver la información del archivo, no es necesario memorizarlo de memoria, debe consultar el documento api
El siguiente es un ejemplo de API para obtener información común sobre archivos
public void info(){
File file = new File("d:\\IOTest\\test1.txt");
System.out.println("文件名字="+file.getName());
System.out.println("文件的绝对路径="+file.getAbsolutePath());
System.out.println("文件父级目录="+file.getParent());
System.out.println("文件大小(字节)="+file.length());
System.out.println("文件是否存在="+file.exists());
System.out.println("是不是一个文件="+file.isFile());
System.out.println("是不是一个目录="+file.isDirectory());
}
eliminación de archivos
Simplemente especifique la ruta del archivo, cree un objeto de archivo y llame al método de eliminación para completar la eliminación. Al eliminar un directorio, debe asegurarse de que esté vacío; de lo contrario, la eliminación fallará, pero no se producirá ninguna excepción.
String filePath = "d:\\IOTest\\test2.txt";
File file = new File(filePath);
if(file.exists()){
if(file.delete()){
System.out.println(filePath+"删除成功");
}else{
System.out.println(filePath+"删除失败");
}
}else{
System.out.println("该文件不存在...");
}
crear un directorio
Para crear un directorio de primer nivel, puede llamar directamente a mkdir() para crearlo con éxito, pero si está creando un directorio de varios niveles, debe usar mkdirs; de lo contrario, no se podrá crear el directorio, pero no se producirá ninguna excepción. ser arrojado
public void m3(){
String directoryPath = "D:\\demo\\a\\b\\c";
File file = new File(directoryPath);
if(file.exists()){
System.out.println(directoryPath+"存在...");
}else{
if(file.mkdirs()){
System.out.println(directoryPath+"创建成功...");
}else{
System.out.println(directoryPath+"创建失败");
}
}
}
Principio de flujo IO y clasificación de flujo
concepto de OI
I/O es la abreviatura de Input/Output. La tecnología I/O es una tecnología muy práctica para procesar la transmisión de datos, la comunicación en red y la lectura y escritura de archivos. El paquete java.io proporciona clases e interfaces para varias interfaces de flujo. Se utiliza para procesar diferentes datos y datos de entrada o salida a través de api
Entrada Entrada: se refiere a la entrada de datos del disco a la memoria
Salida Salida: se refiere a la salida de datos de la memoria al disco
Clasificación de flujos IO
Clasificados por tipo de datos de operación: divididos en flujo de bytes (procesamiento de archivos binarios como audio, imágenes, video, etc.) y flujo de caracteres (procesamiento de texto)
Según la dirección del flujo del flujo de datos: dividido en flujo de entrada y flujo de salida
Clasificado según el rol del flujo: flujo de nodo, flujo de procesamiento/flujo de empaquetado (modo decorador)
clase base abstracta | flujo de bytes | flujo de caracteres |
---|---|---|
flujo de entrada | Flujo de entrada | Lector |
flujo de salida | Flujo de salida | Escritor |
archivos y flujos
Los archivos y los flujos son equivalentes a la relación entre productos y paquetes. Los productos deben empaquetarse en paquetes antes de que puedan transportarse, y la información de los archivos también debe convertirse en flujos antes de que puedan transmitirse entre el disco y la memoria. Paquetes ya contienen productos básicos. Si copia Para productos básicos, solo necesita copiar un paquete idéntico. Es por eso que al copiar un archivo, solo necesita copiar el flujo de entrada correspondiente del archivo al flujo de salida. La razón es que el flujo de entrada ya tiene toda la información del archivo antes de poder copiar el archivo.
Clases de flujo de E/S comúnmente utilizadas
flujo de entrada de bytes InputStream
InputStream como clase principal abstracta tiene principalmente las siguientes subclases
Flujo de entrada de FileInputStream
El archivo hello.txt con hello world se prepara de antemano en el disco D. En este momento, los enteros leídos son los valores ASCII de cada carácter. El método de lectura devolverá -1 después de leer el final del archivo, lo que indica que no hay más bytes para leer.
String filePath = "d:\\hello.txt";
int readDate = 0;
//提升作用域,用于在finally关闭输入流
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(filePath);
//一次读入一个字节,读到最后返回-1,表示无数据
while ((readDate = fileInputStream.read()) != -1) {
//每次将读入的字节数据转化为字符并输出
System.out.print((char) readDate);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//关闭流
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
El método anterior genera un problema, es decir, cada vez que se accede al disco desde la memoria, solo se puede leer un byte, y se necesitan 11 bytes para acceder al disco 11 veces. Los estudiantes que han estudiado el sistema operativo saben que acceder al disco de la memoria es muy difícil Una acción requiere mucho tiempo, por lo que para resolver este problema, el diseñador de Java proporciona un método de sobrecarga del búfer en el método read() de FileInputStream, que puede especificar el tamaño de el búfer para determinar el tamaño del búfer que se puede leer en un acceso al disco El número de bytes, lo que reduce el número de accesos al disco y optimiza el rendimiento.
String filePath = "d:\\hello.txt";
int readDate = 0;
// 指定一个8字节的字节数组作为缓冲区
byte[] buf = new byte[8];
FileInputStream fileInputStream = null;
int readLen = 0;
try {
fileInputStream = new FileInputStream(filePath);
while ((readLen = fileInputStream.read(buf)) != -1) {
// 每次将读取到的字节数据转为字符串输出
System.out.print(new String (buf,0,readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Podemos ver que 8 caracteres de ASCII se leen directamente en la matriz de bytes del búfer
Pero sin un búfer, solo se puede leer uno a la vez, y la brecha de rendimiento es grande
Flujo de salida de bytes OutputStream
FileOutputStream
De forma predeterminada, el método de escritura de FileOutputStream es sobrescribir el contenido del archivo original. Si desea utilizar el método de escritura de anexar, debe asignar append a verdadero al crear el objeto para habilitar el modo de escritura de anexar. Al mismo tiempo, cuando el archivo no existe, el archivo se creará automáticamente, pero asegúrese de que el directorio existe
String filePath = "d:\\IOTest\\outTest.txt";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(filePath,true);
String str = "hello,world";
fileOutputStream.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Use FileOutputStream y FileInputStream para realizar la copia de archivos
Los pasos generales se dividen en dos pasos.
- Cree un flujo de entrada para un archivo y lea el archivo en el programa
- Cree el flujo de salida del archivo y escriba los datos del archivo leído en el archivo especificado
//文件路径
String srcFilePath = "D:\\IOTest\\3e405d5c5b640f81caac8b4e551f7f33841232cd_raw.jpg";
//拷贝的文件路径
String destFilePath = "D:\\IOTest\\kakaxi.jpg";
//输出流
FileOutputStream fileOutputStream = null;
//输入流
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(srcFilePath);
fileOutputStream = new FileOutputStream(destFilePath);
//开辟1024个字节的缓冲区
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = fileInputStream.read(buf)) != -1){
//将读到的文件信息写入新文件
fileOutputStream.write(buf,0,readLen);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//判断非空,防止出现空指针异常
if(fileInputStream!=null){
fileInputStream.close();
}
if(fileOutputStream!=null){
fileOutputStream.close();
}}catch (IOException e) {
e.printStackTrace();
}
}
copia normal de archivos
Flujo de entrada de caracteres FileReader
API relacionadas
ejemplo de código
String filePath = "d:\\IOTest\\story.txt";
FileReader fileReader = null;
int date = 0;
try {
fileReader= new FileReader(filePath);
while((date = fileReader.read())!=-1){
System.out.print((char)date);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
El flujo de caracteres se usa especialmente para procesar archivos de texto. Podemos ver los caracteres leídos por FileReader. No hay caracteres ilegibles en los caracteres chinos. Tenga en cuenta que el método de lectura devuelve el valor ASCII de los caracteres. FileReader también puede especificar el búfer, y la descripción no se repetirá aquí.
Flujo de salida de caracteres FileWriter
API relacionadas
ejemplo de código
String filePath = "d:\\IOTest\\note.txt";
FileWriter fileWriter = null;
char[] chars = {
'a', 'b', 'c'};
try {
fileWriter = new FileWriter(filePath);
fileWriter.write('H');
fileWriter.write("学java狠狠赚一笔");
fileWriter.write(chars);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 对于FileWriter,一定要关闭流,或者flush才能真正将数据写入到文件中
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
¿Por qué tiene que cerrar la transmisión o ejecutar el vaciado antes de escribir datos?
La razón es que después de ejecutar close, FileWriter en realidad llamará a la interfaz subyacente para la escritura de datos.
Flujo de nodo y flujo de proceso
concepto
Flujo de nodo: puede leer y escribir datos de una fuente de datos específica (archivo), como el anterior FileInputStream, FileWriter
Flujo de proceso: según el flujo existente, proporcione funciones de lectura y escritura más potentes para el programa, es decir, use el patrón de diseño del decorador para expandir la función del flujo original y hacerlo más potente, como BufferedReader, BufferedWriter
Principio de flujo de proceso
¿Por qué el flujo de procesamiento puede encapsular el flujo del nodo original?Tome BufferedWriter como ejemplo
FileWriter hereda la clase Writer y BufferedWriter también hereda la clase Writer
El tipo de datos del atributo de miembro fuera de BufferedWriter es el objeto que Writer puede recibir FilerWriter, que es la encarnación del polimorfismo. Esto muestra que podemos encapsular cualquier flujo de nodo, siempre que el objeto de flujo de nodo sea una subclase de Writer, y lo mismo es cierto para BufferedReader.
flujo de procesamiento
La función de los flujos de procesamiento se refleja principalmente en los siguientes dos aspectos:
- Mejora del rendimiento: principalmente aumentando el almacenamiento en búfer para mejorar la eficiencia de entrada y salida.
- Conveniencia de operación: el flujo de procesamiento puede proporcionar una serie de métodos convenientes para ingresar y generar una gran cantidad de datos a la vez, como su propio búfer, lo que mejora el rendimiento de lectura y es más flexible y conveniente de usar.
BufferedReader
API relacionadas
ejemplo de código
Al crear un objeto BufferedReader, debe pasar el objeto de flujo de nodo correspondiente y cerrar el flujo externo. Llamar al método de cierre de BufferedReader también llamará al método de cierre del flujo de nodo para cerrar el flujo.
String filePath = "d:\\IOTest\\note.txt";
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
String line = "";
//按行读取效率高,返回null时表示读取完成
while((line=bufferedReader.readLine())!=null){
System.out.println(line);
}
//关闭外层流即可
bufferedReader.close();
BufferedWriter
API relacionadas
ejemplo de código
String filePath = "d:\\IOTest\\ok.txt";
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));
bufferedWriter.write("hello,你好世界~");
bufferedWriter.newLine();//系统换行
bufferedWriter.write("hello,你好~");
bufferedWriter.newLine();
bufferedWriter.write("hello,你好世界~");
bufferedWriter.newLine();
bufferedWriter.close();
BufferedOutputStream y BufferedInputStream
BufferedInputStream: flujo de bytes, al crear BufferedInputStream creará automáticamente una matriz de búfer, es decir, no necesitamos crear manualmente un búfer
BufferedOutputStream: secuencia de bytes, que implementa una secuencia de salida almacenada en búfer, puede escribir varios bytes en la secuencia de salida subyacente sin tener que llamar al sistema subyacente para cada escritura de byte
flujo de procesamiento de objetos
usar
Cuando necesitamos guardar su tipo al guardar datos y restaurar el objeto o el tipo de datos en el archivo, debemos poder serializar y deserializar el tipo de datos u objeto básico. En este momento, necesitamos usar el flujo de procesamiento de objetos. Realizar manipulación de datos
Serialización y deserialización
Serialización: La serialización es guardar el valor y el tipo de datos de los datos al guardar los datos
Deserialización: La deserialización es restaurar el valor y el tipo de datos de los datos al restaurar los datos
Condiciones para realizar la serialización
Para lograr la serialización, una clase debe implementar la interfaz Serializable, y todas las clases contenedoras de los tipos de datos básicos de Java implementan la interfaz Serializable.
ObjectOutputStreamObjectOutputStream
API relacionadas
Se proporcionan una serie de API para facilitarnos la salida de tipos de datos básicos y clases personalizadas.
ejemplo de código
public static void main(String[] args) throws Exception{
String filePath = "d:\\IOTest\\data.dat";
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream(filePath));
oos.writeInt(100);
oos.writeBoolean(true);
oos.writeChar('a');
oos.writeDouble(9.5);
oos.writeUTF("jack");
oos.writeObject(new Dog("旺财",10));
oos.close();
System.out.println("数据保存完毕(序列化形式)");
}
}
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Debido a que es un flujo de bytes, está distorsionado porque no se ha convertido en una codificación, pero aún podemos ver que el tipo es Dog
ObjetoEntradaStream
API relacionadas
ejemplo de código
String filePath = "d:\\IOTest\\data.dat";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
Object dog = ois.readObject();
System.out.println("运行类型为:"+dog.getClass());
System.out.println(dog);
ois.close();
System.out.println();
flujo de conversión
necesidad
Cuando leemos un archivo a través de FileInputStream, cuando leemos chino, habrá caracteres ilegibles, como se muestra en la figura, se convertirán en caracteres ilegibles, por lo que debemos convertir la secuencia para especificar el formato de codificación.
InputStreamReader
InputStreamReader, como una subclase de Reader, puede envolver InputStream (flujo de bytes) en (convertir) Reader (flujo de caracteres)
Constructor y API
La característica más importante es que podemos especificar el formato de codificación de la transmisión.
ejemplo de código
String filePath = "d:\\IOTest\\note.txt";
//创建输入转化流InputStreamReader对象,同时指定编码为utf-8
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "utf-8");
//包装成BufferedReader对象进行字符读取操作
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String s = bufferedReader.readLine();
System.out.println("读取内容="+s);
bufferedReader.close();
Podemos ver otro gran dinero
OutputStreamWriter
OutputStreamWriter: una subclase de Writer, que realiza el empaquetado de OutputStream (flujo de bytes en Writer).
Métodos de construcción y API relacionadas
ejemplo de código
String filePath = "d:\\IOTest\\hello.txt";
//指定编码
String charSet="utf8";
//包装流
OutputStreamWriter outputStreamWriter =
new OutputStreamWriter(new FileOutputStream(filePath), charSet);
outputStreamWriter.write("hello world 你好世界");
outputStreamWriter.close();
System.out.println("按照 "+charSet+" 保存文件成功~");
flujo de impresión
PrintStream y PrintWriter
API relacionadas
PrintStream imprime el contenido en la pantalla de forma predeterminada, pero podemos especificar la ubicación de salida a través del constructor, como enviar el contenido a un archivo
ejemplo de código
PrintStream out = System.out;
out.print("john,hello");
out.write(" 你好".getBytes());
out.close();
//修改输出位置
System.setOut(new PrintStream("d:\\f1.txt"));
System.out.println("hello,你好世界");