Java IO 流全介绍

java 流概述

  • 流根据方向可以分为:输入流和输出流
    • 注意:输入和输出是相对于内存而言的
    • 从内存中出来就是输出,到内存中就是输入
    • 输入流 又叫做 InputStream
    • 输出流又叫做 OutputStream
    • 输入 还叫作"读",Read
    • 输出还叫作“写”, Write
  • 流根据读取数据的方式可以分为:字节流和字符流
    • 字节流是按照字节的方式读取
    • 字符流是按照字符的方式读取,一次读 2 个字节
      • java 语言中一个字符 占 2 个字节
    • 字节流适合读取:视频、声音、图片等二进制文件
    • 字符流适合读取:纯文本文件
    • Java语言中所有的字节流都以Stream结尾
    • 所有的字符流都含有Reader或者Writer

在这里插入图片描述

  • 需要重点掌握的16个流

    java.io.*;
    
    FileInputStream
    FileOutputStream
    FileReader
    FileWriter
    
    BufferedInputStream
    BufferedOutputStream
    BufferedReader
    BufferedWriter
    
    DataInputStream
    DateOutputStream
    
    ObjectInputStream
    ObjectOutputStream
    
    转换流(字节流转换成字符流)
    InputStreamReader
    OutputStreamWriter
    
    PrintWriter
    PrintStream // 标准的输出流(默认输出到控制台)
    
    
  • Java语言中的流分为四大家族

    • InputStream
    • OutputStream
    • Reader
    • Writer
  • InputStreamOutputStream 继承结构图

InputStream&OutputStream继承结构图

  • ReaderWriter 继承结构图

    Reader&Writer继承结构图

文件流

FileInputStream
  • 继承结构

    java.io.InputStream;
    --- java.io.FileInputStream; // 文件字节输入流
    

    按照字节方式读取文件

  • 举例1-使用read()方法 一次读取一个字节

    FileInputStream构造方法Read
    该方法返回的int 类型的值表示读取的字节。

    import java.io.*;
    
    public class Test01 {
    	public static void main(String[] args){
    		FileInputStream fis = null;
    		// 1. 要读取文件,先与这个文件创建一个输入流
    		// 文件路径
    		String filePath = "D:\\CodeFiles\\CodeTrain\\code_train\\src\\com\\test\\inputoutput\\temp01";
    		try {
    			fis = new FileInputStream(filePath);
    			// 2. 开始读
    			// int read() // --> Reads a byte of data from this input stream.
    			int i1 = fis.read();// 以字节的方式读取
    			int i2 = fis.read();// 以字节的方式读取
    			int i3 = fis.read();// 以字节的方式读取
    			int i4 = fis.read();// 以字节的方式读取
    			int i5 = fis.read();// 以字节的方式读取
    			int i6 = fis.read();// 以字节的方式读取
    			int i7 = fis.read();// 以字节的方式读取
    			int i8 = fis.read();// 以字节的方式读取
    			System.out.println(i1);// a -> 97
    			System.out.println(i2);// b -> 98
    			System.out.println(i3);// c -> 99
    			System.out.println(i4);// d -> 100
    			System.out.println(i5);// e -> 101
    			System.out.println(i6);// f -> 102
    			System.out.println(i7);// 结束 -> -1
    			System.out.println(i8);// 结束 -> -1	
    		}catch(FileNotFoundException e) {
    			e.printStackTrace();
    		}catch(IOException e){
    			e.printStackTrace();
    		}finally {
    			try {
    				fis.close();
    			}catch(IOException e) {
    				e.printStackTrace();
    			}
    		}	
    	}
    }
    /*输出
    97
    98
    99
    100
    101
    102
    -1
    -1
    */
    
    • 测试

      import java.io.*;
      public class Test02 {
      	public static void main(String[] args) throws Exception{
      		// 1. 创建文件流
      		// 文件路径
      		String filePath = "D:\\CodeFiles\\CodeTrain\\code_train\\src\\com\\test\\inputoutput\\temp01";
      		FileInputStream fis = new FileInputStream(filePath);
      		// 2. 读
      		while(true) {
      			int temp = fis.read();
      			if(-1 == temp) {
      				break;
      			}
      			System.out.println(temp);
      		}
              // 3. 关闭流
      		fis.close();
      	}
      }
      /*输出
      97
      98
      99
      100
      101
      102
      */
      
    • 测试

      import java.io.*;
      
      public class Test03 {
      	public static void main(String[] args) throws Exception{
      		// 1. 创建文件流
      		// 文件路径
      		String filePath = "D:\\CodeFiles\\CodeTrain\\code_train\\src\\com\\test\\inputoutput\\temp01";
      		FileInputStream fis = new FileInputStream(filePath);
      		// 2. 读
      		int temp = 0;
      		while((temp = fis.read()) != -1) {
      			System.out.println(temp);
      		}
              // 3. 关闭流
      		fis.close();
      	}
      }
      /*输出
      97
      98
      99
      100
      101
      102
      */
      
    • 使用read()方法读取文件数据的缺点

      • 效率较低,一次只能读取1字节
      • 频繁访问磁盘,对磁盘伤害较大
  • 举例2- 使用 read(byte[] b)读取文件,每次都读取固定长度的字节存储到字节数组中

在这里插入图片描述

int read(byte[] b);
读取之前在内存中准备一个 byte 类型的数组,每次读取多个字节存储在 byte 数组中。
一次读取多个字节,不是单字节读取了,效率较高

该方法返回的int类型的值代表的是:该次读取了多少字节

  • 如果没有读取到,即已经到达了文件的末尾,则返回 -1
import java.io.*;
public class Test04 {
	public static void main(String[] args) throws Exception{
		// 1. 创建输入流
		String filePath = "D:\\CodeFiles\\CodeTrain\\code_train\\src\\com\\test\\inputoutput\\temp01";
		FileInputStream fis = new FileInputStream(filePath);
		// 2. 读
		byte[] bytes = new byte[3];// 每一次最多读取3个字节
		int i1 = fis.read(bytes); // 3
        // byte数组转换成字符串
		System.out.println(new String(bytes));//abc
		int i2 = fis.read(bytes); // 3 
		System.out.println(new String(bytes));// def
		int i3 = fis.read(bytes); // 1
		System.out.println(new String(bytes, 0, i3));// g
		int i4 = fis.read(bytes); // -1 已经到达文件末尾, 返回 -1
		// 3. 关闭
		fis.close();
	}
}
  • 测试-使用循环读取

    import java.io.*;
    
    public class Test05 {
    	public static void main(String[] args) throws Exception{
    		String filePath ="D:\\CodeFiles\\CodeTrain\\code_train\\src\\com\\test\\inputoutput\\temp01";
    		FileInputStream fis = new FileInputStream(filePath);
    		byte[] bytes = new byte[1024];// 每次最读取1024字节
    		while(true) {
    			int temp= fis.read(bytes);
    			if(-1 == temp) {
    				break;
    			}
    			// 讲byte中有效的数据转换成字符串
    			System.out.println(new String(bytes, 0, temp));
    		}
    		fis.close();
    	}
    }
    // 输出
    // abcdefg
    
  • 测试-使用循环读取

    import java.io.*;
    public class test06 {
    	public static void main(String[] args) throws Exception{
    		String filePath = "D:\\CodeFiles\\CodeTrain\\code_train\\src\\com\\test\\inputoutput\\temp01";
    		FileInputStream fis = new FileInputStream(filePath);
    		int temp =0;
    		byte[] bytes = new byte[1024];
    		while((temp = fis.read(bytes)) != -1) {
    			System.out.println(new String(bytes, 0, temp));
    		}
    		fis.close();
    	}
    }
    
  • 举例3-使用available()方法 返回流中剩余的估计字节数,使用 skip(long n)方法跳过 n 个字节

    import java.io.*;
    
    public class Test07 {
    	public static void main(String[] args) throws Exception{
    		String filePath = "D:\\CodeFiles\\CodeTrain\\code_train\\src\\com\\test\\inputoutput\\temp01";
    		FileInputStream fis = new FileInputStream(filePath);
    		int i1 = fis.available();
    		System.out.println(i1); // 7
    		int i2 = fis.read();// 读取一个字节:a-97
    		int i3 = fis.available();// 剩余的估计字节数
    		System.out.println(i3);// 6
    		long l1 = fis.skip(2); // 返回实际跳过的字节数
    		System.out.println(l1);//2
    		int i4 = fis.available();//4
    		System.out.println(i4);
    		int i5 = fis.read();
    		System.out.println(i5);// d-100
    		fis.close();
    	}
    }
    
    
FileOutputStream
  • 继承结构

    java.io.OutputStream;
    ---- java.io.FileOutputStream; // 文件字节输出流
    

    将计算机内存中的数据写入硬盘文件中。

  • 构造方法
    在这里插入图片描述

  • 举例1-使用 FileOutputStream(String name) 方法覆盖原始文件内容

    import java.io.*;
    public class Test08 {
    	public static void main(String[] args) {
    		String filePath = "temp02";
    		FileOutputStream fos = null;
    		try {
    			// 创建文件字节输出流
    			fos = new FileOutputStream(filePath);// 文件不存在则自动创建
    			// 开始写数据
    			String msg = "HelloWorld";
    			// 字符串转换为byte数组
    			byte[] bytes = msg.getBytes();
    			fos.write(bytes);
    			// 推荐最后的时候为了保证数据完全写入硬盘,执行刷新函数
    			fos.flush();// 强制写入
    		}catch(Exception e) {
    			e.printStackTrace();
    		}finally {
    			if(fos != null) {
    				try {
    					fos.close();
    				}catch(IOException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
    
  • 举例2-使用使用 FileOutputStream(String name, boolean append)方法在原来的文件后面追加数据

    import java.io.*;
    public class Test09 {
    	public static void main(String[] args) throws Exception{
    		String filePath = "temp02";
    		// 创建文件字节输出流
    		// 在文件末尾追加数据
    		FileOutputStream fos = new FileOutputStream(filePath, true);
    		String msg = "helloWorld!!";
    		// 字符串转换为 bytep[]
    		byte[] bytes = msg.getBytes();
    		// 写
    		fos.write(bytes);
    		// 写一部分数据 void write(byte[] b, int off, int len)
    		fos.write(bytes, 2, 3);
    		fos.flush();
    		fos.close();
    	}
    }
    
    
  • 举例3-实现文件的复制粘贴

    import java.io.*;
    
    public class Test10 {
    	public static void main(String[] args) throws Exception{
    		// 创建输入流
    		FileInputStream fis = new FileInputStream("D:\\personalData\\music\\music163\\Aki阿杰 - 一世妆.mp3");
    		// 创建输出流
    		FileOutputStream fos = new FileOutputStream("test.mp3");
    		// 一边读,一边写
    		byte[] bytes = new byte[1024];
    		int temp = 0;
    		while((temp=fis.read(bytes)) != -1) {
    			fos.write(bytes, 0, temp);
    		}
    		
    		// 刷新
    		fos.flush();
    		// 关闭流
    		fis.close();
    		fos.close();
    	}
    }
    
FileReader
  • 继承结构

    java.io.Reader;
    	java.io.InputStreamReader;	// 转换流(字节输入流--> 字符输入流)
    		java.io.FileReader;   // 文件字符输入流
    
  • 举例1-读取纯文本文件

    import java.io.*;
    
    public class Test11 {
    	public static void main(String[] args) {
    		// 创建文件字符输入流
    		FileReader fr = null;
    		try {
    			fr = new FileReader("temp02");
    			char[] ch = new char[512];
    			int temp = 0;
    			while((temp = fr.read(ch)) != -1) {
    				System.out.println(new String(ch, 0, temp));
    			}
    		}catch(Exception e) {
    			e.printStackTrace();
    		}finally {
    			if(fr != null) {
    				try {
    					fr.close();
    				}catch(Exception e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
    
FileWriter
  • 继承结构图

    java.io.Write;
    	java.io.OutputStreamWriter;//转换流(字节输出流转换成字符输出流)
    		java.io.FileWriter;// 文件字符输出流
    
  • 举例1-写文件

    import java.io.*;
    public class Test12 {
    	public static void main(String[] args) throws Exception{
    //		FileWriter fw = new FileWriter("temo03");
    		FileWriter fw = new FileWriter("temo03", true);
    		//写
    		String str = "巴拉巴西";
    		fw.write(str);
    		char[] nchr = {'我','是','中'}; 
    		fw.write(nchr, 0, 2);
    		// 刷新
    		fw.flush();
    		// 关闭
    		fw.close();
    	}
    }
    
    
  • 举例2-使用FileReaderFileWriter实现文件的复制粘贴

    import java.io.*;
    
    public class Test13 {
    	public static void main(String[] args) throws Exception{
    		// 创建文件字符输入流
    		FileReader fr = new FileReader("temp02");
    		// 创建字符输出流
    		FileWriter fw = new FileWriter("temp03");
    		
    		int temp = 0;
    		char[] ncha = new char[512];
    		while((temp = fr.read(ncha))!=-1) {
    			fw.write(ncha, 0, temp);
    		}
    		// 刷新
    		fw.flush();
    		// 关闭
    		fr.close();
    		fw.close();
    	}
    }
    
    

缓冲流

BufferedInputStream

不说了,参照BufferedReader

BufferedOutputStream

不说了,参照BufferedWriter

BufferedReader
  • 继承结构

    java.io.Reader;
    	java.io.BufferedReader;
    
  • 构造方法

    • Reader是一个抽象类,抽象类不能实例化,所以可以使用 FileReader文件字符输入流

在这里插入图片描述

  • 举例1-使用带缓冲区的字符输入流读文件

    import java.io.*;
    public class Test14 {
    	public static void main(String[] args) throws Exception{
    		FileReader fr = new FileReader("temp02");//创建一个文件字符输入流
    		BufferedReader br = new BufferedReader(fr);// 将文件字符输入流包装成带有缓冲区的字符输入流
    		
    		// 开始读
    		String temp = null;
    		while((temp=br.readLine())!=null) {// br.readline();方法读取一行,但是行尾不带换行符
    			System.out.println(temp);// 输出一行
    		}
    		// 关闭
    		// 注意:关闭只需要关闭最外层的包装流(这里有一个装饰者模式)
    		br.close();
    	}
    }
    
    
    • 根据流出现的位置,可以分为:包装流或者处理流 和 节点流
    • FileReader fr是一个节点流
    • BufferedReader br是一个包装流或者处理流
    • readline() 方法读取一行时,不会读取换行符
  • 举例2-使用InputStreamReader转换流将字节输入流转换成字符输入流传入到BufferedReader()

    import java.io.*;
    public class Test15 {
    	public static void main(String[] args) throws Exception {
    		FileInputStream fis = new FileInputStream("temp02");// 文件字节输入流
    		// 转换流,将字节输入流转换成字符输入流
    		InputStreamReader isr = new InputStreamReader(fis);// isr是字符流
    		BufferedReader br = new BufferedReader(isr);
    		//br = new BufferedReader(new InputStreamReader(new FileInputStream("temp02")));
    		// 开始读
    		String temp = null;
    		while((temp = br.readLine())!=null) {
    			System.out.println(temp);
    		}
    		// 关闭
    		// 只需要关闭最外层包装流(装饰者模式)
    		br.close();
    	}
    }
    
  • 举例3-接收用户键盘输入

    import java.io.*;
    public class Test16 {
    	public static void main(String[] args) throws Exception{
    		// System.in 是一个标准字节输入流,默认接收键盘的输入
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		String str = br.readLine();
    		System.out.println(str);
    	}
    }
    
    
BufferedWritter
  • 继承结构

    java.io.Writer;
    	java.io.BufferedWriter;
    
  • 举例1-使用带缓冲区的字符输出流实现文件写操作

    import java.io.*;
    public class Test17 {
    	public static void main(String[] args) throws Exception{
    		BufferedWriter bw = new BufferedWriter(new FileWriter("temp04", true));
    		bw.write("hello world");
    		bw.newLine();// 写入换行符
    		bw.write("嘻嘻哈哈和");
    		bw.flush();
    		bw.close();
    	}
    }
    
    
  • 举例2- 使用BufferedReaderBufferedWriter 实现文件的拷贝

    import java.io.*;
    public class Test18 {
    	public static void main(String[] args) throws Exception{
    		BufferedReader br = new BufferedReader(new FileReader("temp04"));
    		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("temp05")));
    		String temp = null;
    		while((temp=br.readLine())!=null) {
    			bw.write(temp);
    			bw.newLine();
    		}
    		
    		bw.flush();
    		br.close();
    		bw.close();
    	}
    }
    
    

装饰着模式(Decorator)

  • 如何实现对类中某一个方法的扩展(不改变原来的类)?

    • 继承(泛化关系,耦合度较高)

      public class FileReader{
          void close(){
              System.out.println("fileReader closed!");
          }
      }
      
      public class BufferedReader extends FileReader{
          // 扩展 FileReader 里面的close() 方法
          void close(){
              System.out.println("BufferedReader closed");
              super.close();
              System.out.println("BufferedReader closed");
          }
      }
      
      public class Test{
          public static void main(String[] args){
              BufferedReader br = new BufferedReader();
              br.close();
          }
      }
      
    • 装饰者模式(关联关系,耦合度低)

      • 装饰者模式中要求:装饰者中含有被装饰者的引用
      • 装饰者模式中要求:装饰者和被装饰者应该实现同一个类型
      public abstract class Reader {
      	public abstract void close();
      }
      
      
      public class FileReader extends Reader{
      
      	@Override
      	public void close() {
      		System.out.println("FileReader closed!");
      	}
      	
      }
      
      
      public class BufferedReader extends Reader{
      
      	private Reader in;//被装饰者的引用
      	
      	public BufferedReader(Reader in) {// 多态
      		this.in = in;
      	}
      	
      	@Override
      	public void close() {
      		System.out.println("BufferedReader closed!");
      		in.close();
      		System.out.println("BufferedReader closed!");
      	}
      
      }
      
      

数据字节流

DataOutpurStream 和 DataInputStream

数据字节输出流和数据字节输入流是比较专用的流。主要用于存储变量等(用的比较少)

  • DataOutputStream

    java.io.OutputStream;
        java.io.FilterOutputStream;
    		java.io.DataOutputStream;
    

    数据字节输出流可以将 内存中的 “int i=10;” 写入到硬盘文件中。写进去的不是字符串格式,而是二进制串,带有数据类型。

    import java.io.*;
    public class Test19 {
    	public static void main(String[] args) throws Exception{
    		// 创建流
    		DataOutputStream dos = new DataOutputStream(new FileOutputStream("./resource/temp06"));
    		// 准备数据
    		byte b = 10;
    		short s = 13;
    		int i = 24;
    		long l = 123L;
    		float f = 0.23f;
    		double d = 1.32;
    		boolean flag = true;
    		char c = 'a';
    		// 写
    		dos.writeByte(b);
    		dos.writeShort(s);
    		dos.writeInt(i);
    		dos.writeLong(l);
    		dos.writeFloat(f);
    		dos.writeDouble(d);
    		dos.writeBoolean(flag);
    		dos.writeChar(c);
    		// 刷新
    		dos.flush();
    		// 关闭
    		dos.close();
    	}
    
    }
    
  • DataInputStream

    java.io.InputStream;
    	java.io.FilterInputStream;
    		java.io.DataInputStream;
    

    数据字节输入流:用于读取DataOutputStream写的文件,且必须提前知道该文件中的数据存储格式和存储顺序,读取的顺序必须和写入的顺序相同。

    package com.test.inputoutput;
    import java.io.*;
    public class Test20 {
    	public static void main(String[] args) throws Exception{
    		DataInputStream dis = new DataInputStream(new FileInputStream("./resource/temp06"));
    		byte b = dis.readByte();
    		short s = dis.readShort();
    		int i = dis.readInt();
    		long l = dis.readLong();
    		float f = dis.readFloat();
    		double d = dis.readDouble();
    		boolean flag = dis.readBoolean();
    		char c = dis.readChar();
    		
    		System.out.println(b);
    		System.out.println(s);
    		System.out.println(i);
    		System.out.println(l);
    		System.out.println(f);
    		System.out.println(d);
    		System.out.println(flag);
    		System.out.println(c);
    		dis.close();
    	}
    }
    
    
    //输出
    10
    13
    24
    123
    0.23
    1.32
    true
    a
    

打印流

java.io.PrintStream; // 标准输出流,默认打印到控制台,以字节方式

java.io.PrintWriter; // 标准输出流,默认打印到控制台,以字符方式

  • 举例1-使用printStream
import java.io.*;
import java.text.*;
import java.util.*;

public class Test21 {
	public static void main(String[] args) throws Exception{
		// 默认输出到控制台
		System.out.println("hello world");
		PrintStream ps = System.out;
		ps.println("hello world");
		// 可以改变输出方向
		System.setOut(new PrintStream(new FileOutputStream("./resource/logs", true)));// log 文件
		// 输出
		System.out.println("HAHA");
		// 通常使用上面方式记录日志
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
		System.out.println("m1 方法开始执行"+sdf.format(new Date()));
		m1();
		System.out.println("m1 方法执行结束"+sdf.format(new Date()));
	}
	static void m1() {
		System.out.println("hello");
	}
}

对象流

对象序列化&反序列化

序列化:将堆内存中的对象信息转换为可以存储或者传输的形式的过程(Serial)

反序列化:将硬盘中存储的对象信息加载到JVM内存中(DeSerial)

java.io.ObjectOutputStream; 序列化java对象到硬盘

java.io.ObjectInputStream;将硬盘中的数据“反序列化”到JVM内存

  • 举例1-对象序列化

    import java.io.Serializable;
    
    public class User implements Serializable{
        String name;
        public User(String name){
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "User[name:"+this.name+"]";
        }
    }
    
    import java.io.*;
    
    public class Test{
        public static void main(String[] args) throws Exception{
            User u1 = new User("张三");
            User u2 = new User("李四");
            User u3 = new User("王五");
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("temp07"));
            
            oos.writeObject(u1);
            oos.writeObject(u2);
            oos.writeObject(u3);
            // flush
            oos.flush();
            // close
            oos.close();
        }
    }
    
    • 序列化的对象必须实现Serializable接口
      • Serializable接口内没有定义任何方法,将这类接口称为:标识接口
        • 没有任何方法的接口称为标识接口
        • 类似的接口还有java.lang.Clonable
        • 标识接口的作用
          • 起到标识的作用
          • JVM如果看到了某个对象实现了某个标识接口,会对它**“特殊待遇”**
  • 举例2-反序列化

    import java.io.*;
    public class Test02{
        public static void main(String[] args) throws Exception{
            // 创建反序列化流
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("temp07"));
            // 读
            Object o = ois.readObject();
            System.out.println(o);//User[name:张三]
            o = ois.readObject();
            System.out.println(o);//User[name:李四]
            o = ois.readObject();
            System.out.println(o);//User[name:王五]
            // 关闭
            ois.close();
        }
    }
    
序列化版本号:SerialVersion_UID

考虑这样一种情形:

  • 有一个User类

    public class User implements Serializable{
        
    }
    

    将该类对应的对象序列化

    import java.io.*;
    
    public class Test{
        public static void main(String[] args) throws Exception{
            User u1 = new User();
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("temp07"));
            
            oos.writeObject(u1);
    
            // flush
            oos.flush();
            // close
            oos.close();
        }
    }
    

    编译运行后,对该对象反序列化

    • 但是原先生成 User.class 的类删掉了,原先的 User.java 也重写了,重新编译生成 User.class

      public class User implements Serializable{
          String name;
      }
      
    • 反序列化出现错误:

      Exception in thread "main" java.io.InvalidClassException: User; 
      local class incompatible: 
      stream classdesc serialVersionUID = -7020619477594468968, 
      local class serialVersionUID = 5211548487022640024
      

    产生的原因:因为 User 类 实现了 Serializable 接口,JVM 会特殊待遇:会给该类添加一个属性:

    static final long serialVersionUID=-7020619477594468968
    

    在反序列化的时候,JVM会比较硬盘中存储的对象文件和User.class 中的 SerialVersionUID 是否一样,如果不一样,则会报错。

    之前的User.classSerialVersionUID-7020619477594468968; 序列化后存储到硬盘中的SerialVersionUID也是-7020619477594468968;User.java重写后,jvm给它添加的属性SerialVersionUID的值为:5211548487022640024,所以在反序列化的时候出现错误。

    如何实现在更改原先的类之后,仍可以反序列化对象呢?

    • 不让JVM自动生成,自己写一个序列化版本号

      import java.io.Serializable;
      
      public class User implements Serializable{
          // 手动创建序列化版本号
          static final long serialVersionUID = 123123123L;
          // 下面可以对代码升级
          String name;
          public User(String name){
              this.name = name;
          }
      }
      
  • 如果不想让类中的某一个属性序列化,可以在属性前面添加transient关键字修饰

    import java.io.Serializable;
    
    public class User implements Serializable{
        // 序列化版本号
        static final long serialVersionUID = 123123123L;
        // 下面可以对代码升级
        transient String name; // transient 短暂的,暂时的
        public User(String name){
            this.name = name;
        }
        @Override
        public String toString() {
            return "User[name="+this.name+"]";
        }
    }
    

    反序列化得到结果:

    User[name=null]
    

File 类

  • 继承结构

    java.lang.Object;
    	java.io.File;
    
    • File和流没有关系,通过File不能完成文件的读和写

    • File 是 文件和目录路径名的抽象表现形式

      • 代表的硬盘上的文件夹(Directory)和文件(File)
  • 举例1-File中的常用方法

    import java.io.File;
    import java.util.*;
    import java.text.*;
    public class Test01 {
    	public static void main(String[] args) throws Exception{
    		String parentPath = "D:\\CodeFiles\\CodeTrain\\code_train\\resource";
    		File f1 = new File(parentPath);
    		// 1. 判断是否存在
    		System.out.println(f1.exists());// true
    		// 2. 创建新文件
    		File newFile = new File("newFile.java");
    		System.out.println(newFile.createNewFile());// true
    		// 3.获取新文件对应的绝对路径
    		File newFile2 = newFile.getAbsoluteFile();
    		System.out.println(newFile2.getAbsolutePath());
    		// 4.获得文件名
    		System.out.println(newFile.getName());
    		// 5. 获得父目录
    		System.out.println(newFile2.getAbsoluteFile().getParent());
    		// 6. 判断文件路径是否是绝对路径
    		System.out.println(newFile.getAbsoluteFile().isAbsolute());// true
    		// 7.判断是否是目录
    		System.out.println(newFile.isDirectory());// false
    		// 8.判断是否是文件
    		System.out.println(newFile.isFile());// true
    		// 9.判断文件是否是隐藏文件
    		System.out.println(newFile.isHidden()); // false
    		// 10.获取文件最后一次更改的时间
    		long time = newFile.lastModified();
    		Date date = new Date(time);
    		System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(date));//2020-03-17 17:50:25 084
    		// 11.获取文件对应的长度(大小/字节)
    		System.out.println(newFile.length());// 0
    		System.out.println(newFile.getAbsoluteFile().getParent().length());//33
    		// 12. 获取该目录下的所有文件/目录
    		String[] names = new File(newFile.getAbsoluteFile().getParent()).list();
    		for(String str:names) {
    			System.out.println(str);
    		}
    		File[] files = new File(newFile.getAbsoluteFile().getParent()).listFiles();
    		for(File file:files) {
    			System.out.println(file.getAbsolutePath());
    		}
    		// 13.在指定目录下创建目录
    		File newD = new File(newFile.getParentFile(), "test_dir");
    		if(! newD.exists()) {
    			newD.mkdir();
    		}
    		System.out.println(newD.getAbsolutePath());
    		// 14. 删除对应目录
    		System.out.println(newD.delete());
    		// 15.创建多层目录
    		File multi_dir = new File(newFile.getParentFile(), "a/b/v/c/d/f");
    		if(!multi_dir.exists()) {
    			multi_dir.mkdirs();
    		}
    		System.out.println(multi_dir.getAbsolutePath());
    		
    	}
    }
    
    
  • 举例2-递归遍历目录下所有文件

    import java.io.*;
    public class Test02 {
    	public static void main(String[] args) {
    		String parentPath = "D:\\CodeFiles";
    		File f = new File(parentPath);
    		getFilesR(f);
    	}
    
    	private static void getFilesR(File f) {
    		if(f.isFile()) {
    			return;
    		}
    		File[] files = f.listFiles();
    		for(File file:files) {
    			System.out.println(file);
    			getFilesR(file);
    		}
    		
    	}
    }
    

以上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tailor_long

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值