Java 进阶(5) Java IO流

news2025/2/25 16:26:24

⼀、File类

概念:代表物理盘符中的⼀个⽂件或者⽂件夹。

常见方法:

方法名

描述

createNewFile()

创建⼀个新文件。

mkdir()

创建⼀个新⽬录。

delete()

删除⽂件或空⽬录。

exists()

判断File对象所对象所代表的对象是否存在。

getAbsolutePath()

获取⽂件的绝对路径。

getName()

取得名字。

getParent()

获取⽂件/⽬录所在的⽬录。

isDirectory()

是否是⽬录。

isFile()

是否是⽂件。

length()

获得⽂件的⻓度。

listFiles()

列出⽬录中的所有内容

示例:

//⽂件的相关操作
File f = new File("d:/aaa/bbb.java");
System.out.println("⽂件绝对路径:"+f.getAbsolutePath());
System.out.println("⽂件构造路径:"+f.getPath());
System.out.println("⽂件名称:"+f.getName());
System.out.println("⽂件⻓度:"+f.length()+"字节");

//创建⽂件 createNewFile()
File file=new File("d:\\file.txt");
//System.out.println(file.toString());
if(!file.exists()) {
    boolean b=file.createNewFile();
    System.out.println("创建结果:"+b);
}
System.out.println("是否时⽂件:"+file.isFile());

//⽂件夹的相关操作
File f2 = new File("d:/aaa");
System.out.println("⽬录绝对路径:"+f2.getAbsolutePath());
System.out.println("⽬录构造路径:"+f2.getPath());
System.out.println("⽬录名称:"+f2.getName());
System.out.println("⽬录⻓度:"+f2.length());

//遍历⽂件夹
File dir2=new File("d:\\图⽚");
String[] files=dir2.list();
System.out.println("--------------------------------");
for (String string : files) {
    System.out.println(string);
}

FileFilter接口

FileFilter:⽂件过滤器接⼝

boolean accept(File pathname)。

当调⽤File类中的listFiles()⽅法时,⽀持传⼊FileFilter接⼝接⼝实现类,对获取⽂件进⾏过滤,只有满足条件的⽂件的才可出现在listFiles()的返回值中。

示例:

public class DiGuiDemo {
    public static void main(String[] args) {
        File f = new File("d:\\QF\\test");
        printDir(dir);
    }
    public static void printDir(File dir) {
        // 匿名内部类⽅式,创建过滤器⼦类对象
        File[] files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.getName().endsWith(".java")||pathname.isDirectory();
            }
        });
        
        // 循环打印
        for (File file : files) {
            if (file.isFile()) {
                System.out.println("⽂件名:" + file.getAbsolutePath());
            } else {
                printDir2(file);
            }
        }
    }
}

⼆、什么是IO

⽣活中,你肯定经历过这样的场景。当你编辑⼀个⽂本⽂件,忘记了ctrl+s ,可能⽂件就⽩⽩编辑了。当你电脑上插⼊⼀个U盘,可以把⼀个视频,拷⻉到你的电脑硬盘⾥。那么数据都是在哪些设备上的呢?键盘、内存、硬盘、外接设备等等。

我们把这种数据的传输,可以看做是⼀种数据的流动,按照流动的⽅向,以内存为基准,分为输⼊input 和输出output ,即流向内存是输⼊流,流出内存的输出流。

Java中I/O操作主要是指使⽤java.io包下的内容,进⾏输⼊、输出操作。输⼊也叫做读取数据,输出也叫做作写出数据。

三、IO分类

按照流的流向分,可以分为输入流和输出流;

按照操作单元划分,可以划分为字节流和字符流;

按照流的角色划分为节点流和处理流。

Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系,

Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。

InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。

OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

按操作方式分类结构图:

按操作对象分类结构图:

 

四、字节流

⼀切皆为字节

⼀切⽂件数据(⽂本、图⽚、视频等)在存储时,都是以⼆进制数字的形式保存,都⼀个⼀个的字节,那么传输时⼀样如此。所以,字节流可以传输任意⽂件数据。在操作流的时候,我们要时刻明确,⽆论使⽤什么样的流对象,底层传输的始终为⼆进制数据。

字节输出流

java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到⽬的地。它定义了字节输出流的基本共性功能⽅法。

public void close() :关闭此输出流并释放与此流相关联的任何系统资源。

public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。

public void write(byte[] b):将 b.length字节从指定的字节数组写⼊此输出流。

public void write(byte[] b, int off, int len) :从指定的字节数组写⼊ len字节,从偏移量 off开始输出到此输出流。

public abstract void write(int b) :将指定的字节输出流。

FileOutputStream类

构造⽅法:

public FileOutputStream(File file):创建⽂件输出流以写⼊由指定的 File对象表示的⽂件。

public FileOutputStream(String name): 创建⽂件输出流以指定的名称写⼊⽂件。

1、写出字节:write(int b) ⽅法,每次可以写出⼀个字节数据

2、写出字节数组:write(byte[] b),每次可以写出数组中的数据

3、写出指定⻓度字节数组:write(byte[] b, int off, int len) ,每次写出从off索引开始,len个字节

示例:

 

// 使⽤File对象创建流对象
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);
// 使⽤⽂件名称创建流对象
FileOutputStream fos = new FileOutputStream("b.txt");
// 使⽤⽂件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
// 写出数据:虽然参数为int类型四个字节,但是只会保留⼀个字节的信息写出
fos.write(97); // 写出第1个字节
fos.write(98); // 写出第2个字节
fos.write(99); // 写出第3个字节
// 关闭资源
fos.close();
// 使⽤⽂件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
// 字符串转换为字节数组
byte[] b = "你好中国".getBytes();
// 写出字节数组数据
fos.write(b);
// 关闭资源
fos.close();
// 使⽤⽂件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
// 字符串转换为字节数组
byte[] b = "abcde".getBytes();
// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
fos.write(b,2,2);
// 关闭资源
fos.close();

字节输⼊流

java.io.InputStream抽象类是表示字节输⼊流的所有类的超类,可以读取字节信息到内存中。它定义了字节输⼊流的基本共性功能⽅法。

public void close() :关闭此输⼊流并释放与此流相关联的任何系统资源。

public abstract int read(): 从输⼊流读取数据的下⼀个字节。

public int read(byte[] b): 从输⼊流中读取⼀些字节数,并将它们存储到字节数组 b中 。

FileInputStream类

构造⽅法:

FileInputStream(File file): 通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件

由⽂件系统中的 File对象 file命名。

FileInputStream(String name): 通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该

⽂件由⽂件系统中的路径名 name命名。

1、读取字节:read⽅法,每次可以读取⼀个字节的数据,提升为int类型,读取到⽂件末尾,返回-1

2、使⽤字节数组读取:read(byte[] b),每次读取b的⻓度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1

示例:

// 使⽤File对象创建流对象
File file = new File("a.txt");
FileInputStream fos = new FileInputStream(file);
// 使⽤⽂件名称创建流对象
FileInputStream fos = new FileInputStream("b.txt");
// 使⽤⽂件名称创建流对象
FileInputStream fis = new FileInputStream("read.txt");
// 读取数据,返回⼀个字节
int read = fis.read();
System.out.println((char) read);
read = fis.read();
System.out.println((char) read);
read = fis.read();
System.out.println((char) read);
read = fis.read();
System.out.println((char) read);
read = fis.read();
System.out.println((char) read);
// 读取到末尾,返回-1
read = fis.read();
System.out.println( read);
// 关闭资源
fis.close();
// 使⽤⽂件名称创建流对象
FileInputStream fis = new FileInputStream("read.txt");
// 定义变量,保存数据
int b ;
// 循环读取
while ((b = fis.read())!=-1) {
    System.out.println((char)b);
}
// 关闭资源
fis.close();
// 使⽤⽂件名称创建流对象.
FileInputStream fis = new FileInputStream("read.txt"); // ⽂件中为abcde
// 定义变量,作为有效个数
int len ;
// 定义字节数组,作为装字节数据的容器
byte[] b = new byte[2];
// 循环读取
while (( len= fis.read(b))!=-1) {
    // 每次读取后,把数组的有效字节部分,变成字符串打印
    System.out.println(new String(b,0,len));// len 每次读取的有效字节个数
}
// 关闭资源
fis.close();

综合案例:图⽚复制

//1创建流
//1.1⽂件字节输⼊流
FileInputStream fis=new FileInputStream("d:\\001.jpg");
//1.2⽂件字节输出流
FileOutputStream fos=new FileOutputStream("d:\\002.jpg");
//2⼀边读,⼀边写
byte[] buf=new byte[1024];
int count=0;
while((count=fis.read(buf))!=-1) {
    fos.write(buf,0,count);
}
//3关闭
fis.close();
fos.close();
System.out.println("复制完毕");

五、字符流

字符输⼊流

java.io.Reader 抽象类是表示⽤于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输⼊流的基本共性功能⽅法。

public void close() :关闭此流并释放与此流相关联的任何系统资源。

public int read() : 从输⼊流读取⼀个字符。

public int read(char[] cbuf) : 从输⼊流中读取⼀些字符,并将它们存储到字符数组cbuf中 。

FileReader类

构造方法

FileReader(File file) : 创建⼀个新的 FileReader ,给定要读取的File对象。

FileReader(String fileName) : 创建⼀个新的 FileReader ,给定要读取的⽂件的名称。

构造时使⽤系统默认的字符编码和默认字节缓冲区。

1. 字符编码:字节与字符的对应规则。Windows系统的中⽂编码默认是GBK编码表。idea中UTF-8

2. 字节缓冲区:⼀个字节数组,⽤来临时存储字节数据。

示例:

// 使⽤File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使⽤⽂件名称创建流对象
FileReader fr = new FileReader("b.txt");
// 使⽤⽂件名称创建流对象
FileReader fr = new FileReader("read.txt");
// 定义变量,保存有效字符个数
int len ;
// 定义字符数组,作为装字符数据的容器
char[] cbuf = new char[2];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
    System.out.println(new String(cbuf,0,len));
}
// 关闭资源
fr.close();

字符输出流

java.io.Writer 抽象类是表示⽤于写出字符流的所有类的超类,将指定的字符信息写出到⽬的地。

它定义了字符输出流的基本共性功能⽅法。

void write(int c) 写⼊单个字符。

void write(char[] cbuf) 写⼊字符数组。

abstract void write(char[] cbuf, int off, int len) 写⼊字符数组的某⼀部分,off数组的开始索引,len写的字符个数。

void write(String str) 写⼊字符串。

void write(String str, int off, int len) 写⼊字符串的某⼀部分,off字符串的开始索引,len写的字符个数。

void flush() 刷新该流的缓冲。

void close() 关闭此流,但要先刷新它。

FileWriter类

FileWriter(File file) : 创建⼀个新的 FileWriter,给定要读取的File对象。

FileWriter(String fileName) : 创建⼀个新的 FileWriter,给定要读取的⽂件的名称。

构造时使⽤系统默认的字符编码和默认字节缓冲区。

1、写出字符: write(int b) ⽅法,每次可以写出⼀个字符数据

2、写出字符数组 : write(char[] cbuf) 和 write(char[] cbuf, int off, int len) ,每次可以写出字符数组中的数据,⽤法类似FileOutputStream

3、写出字符串: write(String str) 和 write(String str, int off, int len),每次可以写出字符串中的数据,更为⽅便

因为内置缓冲区的原因,如果不关闭输出流,⽆法写出字符到⽂件中。但是关闭的流对象,是⽆法继续写出数据的。如果我们既想写出数据,⼜想继续使⽤流,就需要flush ⽅法了。

// 使⽤File对象创建流对象
File file = new File("fw.txt");
FileWriter fw = new FileWriter(file);
// 使⽤⽂件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 使⽤⽂件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 写出数据
fw.write(97); // 写出第1个字符
fw.write('b'); // 写出第2个字符
fw.write('C'); // 写出第3个字符
fw.write(30000); // 写出第4个字符,中⽂编码表中30000对应⼀个汉字。
/*
【注意】关闭资源时,与FileOutputStream不同。
如果不关闭,数据只是保存到缓冲区,并未保存到⽂件。
*/
// fw.close();
// 使⽤⽂件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 写出数据,通过flush
fw.write('刷'); // 写出第1个字符
fw.flush();
fw.write('新'); // 继续写出第2个字符,写出成功
fw.flush();
// 写出数据,通过close
fw.write('关'); // 写出第1个字符
fw.close();
fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream
closed
fw.close();
// 使⽤⽂件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 字符串转换为字节数组
char[] chars = "你好中国".toCharArray();
// 写出字符数组
fw.write(chars);
// 写出从索引2开始,2个字节。索引2是'中',两个字节,也就是'中国'。
fw.write(b,2,2); //中国
// 关闭资源
fos.close();
// 使⽤⽂件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 字符串
String msg = "你好中国";
// 写出字符数组
fw.write(msg); //你好中国
// 写出从索引2开始,2个字节。索引2是'中',两个字节,也就是'中国'。
fw.write(msg,2,2); // 中国
// 关闭资源
fos.close();

六、缓冲流

概述

缓冲流,也叫⾼效流,是对4个基本的 FileXxx 流的增强,所以也是4个流,按照数据类型分类:

字节缓冲流: BufferedInputStream , BufferedOutputStream

字符缓冲流: BufferedReader , BufferedWriter

缓冲流的基本原理,是在创建流对象时,会创建⼀个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从⽽提⾼读写的效率。

字节缓冲流

构造⽅法:

public BufferedInputStream(InputStream in) :创建⼀个 新的缓冲输⼊流。
public BufferedOutputStream(OutputStream out) : 创建⼀个新的缓冲输出流。

示例:

// 创建字节缓冲输⼊流
BufferedInputStream bis = new BufferedInputStream(new
FileInputStream("bis.txt"));
// 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new
FileOutputStream("bos.txt"));

效率PK

基本流示例:

public static void main(String[] args) {
    // 记录开始时间
    long start = System.currentTimeMillis();
    // 创建流对象
    try (
            FileInputStream fis = new FileInputStream("jdk8.exe");
            FileOutputStream fos = new FileOutputStream("copy.exe")
    ){
    // 读写数据
        int b;
        while ((b = fis.read()) != -1) {
            fos.write(b);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 记录结束时间
    long end = System.currentTimeMillis();
    System.out.println("普通流复制时间:"+(end - start)+" 毫秒");

}

缓冲流示例:

public static void main(String[] args) {
    // 记录开始时间
    long start = System.currentTimeMillis();
    // 创建流对象
    try (
            BufferedInputStream bis = new BufferedInputStream(new
                    FileInputStream("jdk8.exe"));
            BufferedOutputStream bos = new BufferedOutputStream(new
                    FileOutputStream("copy.exe"));
    ){
        // 读写数据
        //int b;
        //while ((b = bis.read()) != -1) {
        //bos.write(b);
        //}
        // 读写数据
        int len;
        byte[] bytes = new byte[8*1024];
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0 , len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 记录结束时间
    long end = System.currentTimeMillis();
    System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");

}

字符缓冲流

构造方法

public BufferedReader(Reader in) :创建⼀个 新的缓冲输⼊流。
public BufferedWriter(Writer out) : 创建⼀个新的缓冲输出流。

示例:

// 创建字符缓冲输⼊流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));

特有方法

字符缓冲流的基本⽅法与普通字符流调⽤⽅式⼀致,不再阐述,我们来看它们具备的特有⽅法。

BufferedReader: public String readLine() : 读⼀⾏⽂字。

BufferedWriter: public void newLine() : 写⼀⾏⾏分隔符,由系统属性定义符号。

示例1:

// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("in.txt"));
// 定义字符串,保存读取的⼀⾏⽂字
String line = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine())!=null) {
    System.out.print(line);
    System.out.println("------");
}
// 释放资源
br.close();

示例2:

// 创建流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
// 写出数据
bw.write("hello");
// 写出换⾏
bw.newLine();
bw.write("world");
bw.newLine();
bw.write("!");
bw.newLine();
// 释放资源
bw.close();

七、转换流

在IDEA中,使⽤ FileReader 读取项⽬中的⽂本⽂件。由于IDEA的设置,都是默认的 UTF-8编码,所以没有任何问题。但是,当读取Windows系统中创建的⽂本⽂件时,由于Windows系统的默认是GBK编码,就会出现乱码。

示例:

public class ReaderDemo {
    public static void main(String[] args) throws IOException {
        FileReader fileReader = new FileReader("E:\\File_GBK.txt");
        int read;
        while ((read = fileReader.read()) != -1) {
            System.out.print((char)read);
        }
        fileReader.close();
    }
}
输出结果:
���

那么如何读取GBK编码的⽂件呢?

InputStreamReader类

转换流 java.io.InputStreamReader ,是Reader的⼦类,是从字节流到字符流的桥梁。它读取字节,并使⽤指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法

InputStreamReader(InputStream in) : 创建⼀个使⽤默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 创建⼀个指定字符集的字符流。

示例:

// 定义⽂件路径,⽂件为gbk编码
String FileName = "E:\\file_gbk.txt";
// 创建流对象,默认UTF8编码
InputStreamReader isr = new InputStreamReader(new
FileInputStream(FileName));
// 创建流对象,指定GBK编码
InputStreamReader isr2 = new InputStreamReader(new
FileInputStream(FileName) , "GBK");
// 定义变量,保存字符
int read;
// 使⽤默认编码字符流读取,乱码
while ((read = isr.read()) != -1) {
    System.out.print((char)read); // ��Һ�
}
isr.close();
// 使⽤指定编码字符流读取,正常解析
while ((read = isr2.read()) != -1) {
    System.out.print((char)read);// ⼤家好
}
isr2.close();

OutputStreamWriter类

转换流 java.io.OutputStreamWriter ,是Writer的⼦类,是从字符流到字节流的桥梁。使⽤指定

的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造⽅法

OutputStreamWriter(OutputStream in) : 创建⼀个使⽤默认字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName) : 创建⼀个指定字符集的字符流。

示例:

// 定义⽂件路径
String FileName = "out.txt";
// 创建流对象,默认UTF8编码
OutputStreamWriter osw = new OutputStreamWriter(new
FileOutputStream(FileName));
// 写出数据
osw.write("你好"); // 保存为6个字节
osw.close();
// 定义⽂件路径
String FileName2 = "out2.txt";
// 创建流对象,指定GBK编码
OutputStreamWriter osw2 = new OutputStreamWriter(new
FileOutputStream(FileName2),"GBK");
// 写出数据
osw2.write("你好");// 保存为4个字节
osw2.close();

⼋、序列化

概述

Java 提供了⼀种对象序列化的机制。⽤⼀个字节序列可以表示⼀个对象,该字节序列包含该 对象的数据 、 对象的类型 和 对象中存储的属性 等信息。字节序列写出到⽂件之后,相当于⽂件中持久保存了⼀个对象的信息。

反之,该字节序列还可以从⽂件中读取回来,重构对象,对它进⾏反序列化。 对象的数据 、 对象的类型 和 对象中存储的数据信息,都可以⽤来在内存中创建对象。

ObjectOutputStream类

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到⽂件,实现对象的持久存储。

序列化操作

⼀个对象要想序列化,必须满⾜两个条件:

        必须实现Serializable接⼝。

        必须保证其所有属性均可序列化。(transient修饰为临时属性,不参与序列化)

写出对象⽅法

        public final void writeObject (Object obj) : 将指定的对象写出。

示例:

public class Employee implements java.io.Serializable {
    public String name;
    public String address;
    public transient int age; // transient瞬态修饰成员,不会被序列化
    public void addressCheck() {
        System.out.println("Address check : " + name + " -- " + address);
    }
}
public class SerializeDemo{
    public static void main(String [] args) {
        Employee e = new Employee();
        e.name = "zhangsan";
        e.address = "guangzhou";
        e.age = 20;
        try {
            // 创建序列化流对象
            ObjectOutputStream out = new ObjectOutputStream(new
            FileOutputStream("employee.txt"));
            // 写出对象
            out.writeObject(e);
            // 释放资源
            out.close();
            fileOut.close();
            System.out.println("序列化完成"); // 姓名,地址被序列化,年龄没有被序列化。
        } catch(IOException i) {
            i.printStackTrace();
        }
    }
}

ObjectInputStream类

ObjectInputStream反序列化流,将之前使⽤ObjectOutputStream序列化的原始数据恢复为对象。

反序列化操作

如果能找到⼀个对象的class⽂件,我们可以进⾏反序列化操作,调⽤ ObjectInputStream 读取对象的⽅法,

public final Object readObject () : 读取⼀个对象。

public class DeserializeDemo {
    public static void main(String [] args) {
    Employee e = null;
    try {
        // 创建反序列化流
        FileInputStream fileIn = new FileInputStream("employee.txt");
        ObjectInputStream in = new ObjectInputStream(fileIn);
        // 读取⼀个对象
        e = (Employee) in.readObject();
        // 释放资源
        in.close();
        fileIn.close();
    }catch(IOException i) {
        // 捕获其他异常
        i.printStackTrace();
        return;
    }catch(ClassNotFoundException c) {
        // 捕获类找不到异常
        System.out.println("Employee class not found");
        c.printStackTrace();
        return;
    }
    // ⽆异常,直接打印输出
    System.out.println("Name: " + e.name); // zhangsan
    System.out.println("Address: " + e.address); // beiqinglu
    System.out.println("age: " + e.age); // 0
    }
}

注意:

对于JVM可以反序列化对象,它必须是能够找到class⽂件的类。如果找不到该类的class⽂件,则抛出⼀个ClassNotFoundException 异常。

当JVM反序列化对象时,能找到class⽂件,但是class⽂件在序列化对象之后发⽣了修改,那么反序列化操作也会失败,抛出⼀个 InvalidClassException 异常。

发⽣这个异常的原因,该类的序列版本号与从流中读取的类描述符的版本号不匹配 ,serialVersionUID 该版本号的⽬的在于验证序列化的对象和对应类是否版本匹配。

serialVersionUID是⼀个⾮常重要的字段,因为 Java 的序列化机制是通过在运⾏时判断类的

serialVersionUID来验证版本⼀致性的。在进⾏反序列化时,JVM 会把传来的字节流中的

serialVersionUID与本地相应实体(类)的serialVersionUID进⾏⽐较,如果相同就认为是⼀致的,可

以进⾏反序列化,否则就会出现序列化版本不⼀致的异常。

⼀般来说,定义serialVersionUID的⽅式有两种,分别为:

采⽤默认的1L,具体为private static final long serialVersionUID = 1L;

在可兼容的前提下,可以保留旧版本号,如果不兼容,或者想让它不兼容,就⼿⼯递增版本号。

1->2->3.....

根据类名、接⼝名、成员⽅法及属性等来⽣成⼀个64位的哈希字段,例如 private static final long

serialVersionUID = XXXL;

这种⽅式适⽤于这样的场景:

开发者认为每次修改类后就需要⽣成新的版本号,不想向下兼容,操作就是删除原有serialVesionUid

声明语句,再⾃动⽣成⼀下。

第⼆种能够保证每次更改类结构后改变版本号,但还是要⼿⼯去⽣成

public class Employee implements java.io.Serializable {
    // 加⼊序列版本号
    private static final long serialVersionUID = 1L;
    public String name;
    public String address;
    // 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
    public int eid;
    public void addressCheck() {
        System.out.println("Address check : " + name + " -- " + address);
    }
}

九、Properties属性类

常用方法

public Object setProperty(String key, String value) : 保存⼀对属性。
public String getProperty(String key) :使⽤此属性列表中指定的键搜索属性值。
public Set<String> stringPropertyNames() :所有键的名称的集合。
public void load(InputStream inStream) : 从字节输⼊流中读取键值对。

示例1:

// 创建属性集对象
Properties properties = new Properties();
// 添加键值对元素
properties.setProperty("filename", "a.txt");
properties.setProperty("length", "123");
properties.setProperty("location", "D:\\a.txt");
// 打印属性集对象
System.out.println(properties);
// 通过键,获取属性值
System.out.println(properties.getProperty("filename"));
System.out.println(properties.getProperty("length"));
System.out.println(properties.getProperty("location"));
// 遍历属性集,获取所有键的集合
Set<String> strings = properties.stringPropertyNames();
// 打印键值对
for (String key : strings ) {
    System.out.println(key+" -- "+properties.getProperty(key));
}

示例2:

// 创建属性集对象
Properties pro = new Properties();
// 加载⽂本中信息到属性集
pro.load(new FileInputStream("read.txt"));
// 遍历集合并打印
Set<String> strings = pro.stringPropertyNames();
for (String key : strings ) {
    System.out.println(key+" -- "+pro.getProperty(key));
}

小贴士:⽂本中的数据,必须是键值对形式,可以使⽤空格、等号、冒号等符号分隔。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/413222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4.2 方差

学习目标&#xff1a; 我认为学习方差需要以下几个步骤&#xff1a; 确定学习目标&#xff1a;在开始学习方差之前&#xff0c;需要明确学习的目标和意义&#xff0c;例如&#xff0c;理解方差的定义、掌握方差的计算方法、了解方差在实际问题中的应用等。 学习相关数学概念&…

宝塔Linux面板安装命令脚本大全(Centos/Ubuntu/Debian/Fedora/Deepin)

宝塔面板Linux服务器操作系统安装命令大全&#xff0c;包括Centos、Alibaba Cloud Linux、Ubuntu、TencentOS Server、Deepin、Debian和Fedora安装脚本&#xff0c;云服务器吧分享宝塔面板Linux服务器系统安装命令大全&#xff1a; 目录 宝塔面板Linux系统安装命令 Centos安…

【Vue】学习笔记-事件处理

事件的基本用法 使用v-on:xxx 或xxx 绑定事件&#xff0c;其中xxx是事件名事件的回调需要配置在methods对象中&#xff0c;最终会在vm上methods中配置的函数&#xff0c;不要用箭头函数&#xff0c;否则this就不是vm了methods中配置的函数&#xff0c;都是被vue所管理的函数。…

Pandas库:从入门到应用(三)——多表连接操作

一 、concat数据连接 1.1、concat()函数参数 pd.concat(objs, axis0, joinouter, ignore indexFalse, keysNone, levelsNone, namesNoneverify integrityFalse, sort False, copyTrue)objs&#xff1a;多个 DataFrame 或者 Series axis&#xff1a;0-行拼接 1-列拼接 join&am…

011:Mapbox GL两种方式隐藏logo和版权,个性化版权的声明

第011个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中用两种方式隐藏logo和版权,并个性化版权的声明 。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共91行)相关API参考:专栏目标示例效果 配置方式…

2023高性价比学生手机选购攻略,预算不多入手这3款超值

学生党在预算不多的情况&#xff0c;想要换颜值高的新手机&#xff0c;应该选什么样的手机才实惠&#xff1f; 手机已经成为生活中的必需品&#xff0c;市场上的手机品牌和型号多种多样&#xff0c;价格逐年攀升&#xff0c;对于预算有限的学生党来说&#xff0c;在保证性能和…

编译原理期末速成笔记

哈喽大家好&#xff0c;又要考试了&#xff0c;在这里分享一下我的两天速成笔记&#xff0c;参考视频为哔站 Deeplei_ 的《编译原理期末速成》。本文仅是知识点总结&#xff0c;至于考试内容待我研究一下&#xff0c;后续我会再发文对考试的各个模块做详细分析&#xff0c;欢迎…

JavaWeb开发 —— Ajax

目录 一、介绍 二、原生Ajax 三、Axios 四、案例分析 一、介绍 ① 概念&#xff1a;Asynchronous JavaScript And XML&#xff0c;异步的JavaScript和XML。 ② 作用&#xff1a; 数据交换&#xff1a;通过Ajax可以给服务器发送请求&#xff0c;并获取服务器响应的数据。…

多元函数的基本概念——“高等数学”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是多元函数的基本概念&#xff0c;下面&#xff0c;让我们一起进入多元函数的世界吧 平面点集 多元函数的概念 多元函数的极限 多元函数的连续性 有界闭区域上多元连续函数的性质 平面点集 第一个是坐标平…

中间表示- 到达定义分析

基本概念 定义&#xff08;def&#xff09;&#xff1a;对变量的赋值 使用&#xff08;use&#xff09;&#xff1a;对变量值的读取 问题&#xff1a;能把上图中的y替换为3吗&#xff1f;如果能&#xff0c;这称之为“常量传播”优化。 该问题等价于&#xff0c;有哪些对变量y…

R730服务器热插拔换磁盘(raid阵列)

r730服务器发现磁盘闪橙等&#xff0c;说明磁盘报警了&#xff0c;这时候我们就要换磁盘了。 由于本服务器磁盘是raid5的阵列磁盘&#xff0c;所以要采用热插拔的方式换磁盘。 这边要注意的是&#xff0c;不能关机的时候&#xff0c;直接来换磁盘。 因为关机换磁盘&#xff0c…

golang指针相关

指针相关的部分实在是没有搞太明白&#xff0c;抽时间来总结下。 1.指针相关基础知识 比如现在有一句话&#xff1a;『谜底666』&#xff0c;这句话在程序中一启动&#xff0c;就要加载到内存中&#xff0c;假如内存地址0x123456&#xff0c;然后我们可以将这句话复制给变量A&…

什么是服务架构?微服务架构的优势又是什么?

文章目录1.1 单体架构1.2 分布式架构1.3 微服务架构1.4 单体架构和分布式架构的区分1.4 服务架构的优劣点1.4.1 单体架构1.4.2 分布式架构1.4.3 微服务架构1.5 总结1.1 单体架构 单体架构&#xff08;Monolithic Architecture&#xff09;是一种传统的软件架构&#xff0c;它将…

算法学习day56

算法学习day561.力扣583. 两个字符串的删除操作1.1 题目描述1.2分析1.3 代码2.力扣72. 编辑距离2.1 题目描述2.2 分析2.3 代码3.参考资料1.力扣583. 两个字符串的删除操作 1.1 题目描述 题目描述&#xff1a; 给定两个单词word1和word2&#xff0c;找到使得word1和word2相同…

探索数据结构之精髓:单链表解密

文章目录1. 前言2. 单链表的特点3. 单链表的基础操作&#x1f351; 接口总览&#x1f351; 初始化操作&#x1f351; 插入操作&#x1f345; 优化操作&#x1f351; 删除操作&#x1f345; 优化操作&#x1f351; 获取元素&#x1f345; 按置查找&#x1f345; 按值查找&#x…

从C出发 20 --- 函数参数深度剖析

我们在编写这个函数的时候参数 n 的值具体是多少&#xff1f; 在编写一个函数的时候参数值是没法确定的&#xff0c;所以将 (int n) 这个参数命名为形参 那么这个参数的值什么时候指定&#xff0c;具体函数调用的时候指定 比如 在main 里面调用 实参用来初始化形参 初始化之…

安装多个版本的Node.js的方法

要在同一台计算机上安装多个版本的Node.js&#xff0c;可以使用以下几种方法&#xff1a; 使用nvm&#xff08;Node Version Manager&#xff09;&#xff1a;nvm是一个用于管理多个Active Node.js版本的工具。您可以使用nvm轻松地在系统中安装、卸载和切换不同版本的Node.js。…

Leetcode每日一题——“消失的数字”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰又开新专栏了&#xff0c;以后会在Leetcode上面进行刷题&#xff0c;尽量每天写一道&#xff0c;请大家监督我&#xff01;&#xff01;&#xff01;好啦&#xff0c;让我们进入Leetcode的世界吧 力扣 对于这道题目&a…

南卡OE Pro上线!开放式耳机新里程碑!前所未有的音质舒适双冠

当前耳机市场放眼望去几乎都是TWS的天下&#xff0c;但是大多数的蓝牙耳机都存在着以下痛点&#xff1a;长时间佩戴涨耳、出现听诊器效应、耳朵内部发痒以及与外界声音隔开缺乏安全性等等问题。 为此&#xff0c;国内智能声学品牌厂商NANK南卡针对用户的特点&#xff0c;于近日…

中小企业如何实施知识管理策略?

随着信息化建设的深入&#xff0c;IT不仅成为企业运营的基础平台&#xff0c;而且在ERP、CRM、OA等信息系统内沉淀了大量的知识&#xff0c;成为企业创新的源泉&#xff0c;大中企业信息化建设中知识管理越来越重要。 应该如何实现知识管理呢&#xff1f; 知识管理本身就属于企…