JAVA核心技术(2)IO

目录

1、File

2、文件过滤器+遍历文件夹

3、相对路径和绝对路径

4、IO流

4.1、字节流

4.1.1、OutputStream 抽象类

4.1.2、InputputStream 抽象类

4.2、字符流

4.2.1、Writer抽象类

4.2.2、Reader抽象类

4.3、转换流。将字节流装饰为字符流:使用装饰者设计模式

4.4、字符输出打印流、缓冲读取流

4.5、输出错误日志

5、Properties

6、序列化与反序列化

6.1、序列化中忽略不想序列化的属性

6.1.1、transient关键字

6.1.2、static关键字

6.1.3、默认方法实现序列化

6.1.4、Externalizable接口,实现序列化

6.1.5、Serializable接口与Externalizable

7、try-with-resources


1、File

构造器

描述

File​(File parent, String child)

从父抽象路径名和子路径名字符串创建新的 File实例。

File​(String pathname)

通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。

File​(String parent, String child)

从父路径名字符串和子路径名字符串创建新的 File实例。

常用方法:

变量和类型

方法

描述

String

getAbsolutePath()

返回此抽象路径名的绝对路径名字符串。

File

getAbsoluteFile()

返回此抽象路径名的绝对形式。

String

getParent()

返回此抽象路径名父项的路径名字符串,如果此路径名未指定父目录,则返回 null 。

File

getParentFile()

返回此抽象路径名父项的抽象路径名,如果此路径名未指定父目录,则返回 null 。

String

getPath()

将此抽象路径名转换为路径名字符串。

long

length()

返回此抽象路径名表示的文件的长度。单位Byte。1024B = 1KB

boolean

exists()

测试此抽象路径名表示的文件或目录是否存在。

boolean

isDirectory()

测试此抽象路径名表示的文件是否为目录。

boolean

isFile()

测试此抽象路径名表示的文件是否为普通文件。

String[]

list()

返回一个字符串数组,用于命名此抽象路径名表示的目录中的文件和目录。

File[]

listFiles()

返回一个抽象路径名数组,表示此抽象路径名表示的目录中的文件。

boolean

mkdir()

创建此抽象路径名指定的目录,父目录不存在就创建不出来

boolean

mkdirs()

创建此抽象路径名指定的目录,父目录不存在会把父目录创建

boolean

renameTo​(File newFile)

剪切并重命名

boolean

delete()

删除此抽象路径名表示的文件或目录。删除文件要谨慎,删掉不会在回收站

成员属性:不同系统路径用的符号会不同,用这个替代不会出错

变量和类型

字段

描述

static String

pathSeparator

与系统相关的路径分隔符,为方便起见,表示为字符串。

static char

pathSeparatorChar

与系统相关的路径分隔符。

static String

separator

系统相关的默认名称分隔符,为方便起见,表示为字符串。

static char

separatorChar

系统相关的默认名称分隔符。

2、文件过滤器+遍历文件夹

package com.syp.file.test;

import java.io.File;
import java.io.FileFilter;

/**
 * @author suyiping
 * @create 2021-06-23 19:33
 */
public class Test {
    public static void main(String[] args) {
        File file = new File("E:/");
        showFiles(file);
    }

    static void showFiles(File file) {
        File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File f) {
                if ((f.getName().endsWith(".exe") && f.length() > 10 * 1024 * 1024) || f.isDirectory())
                    return true;
                return false;
            }
        });
        if (files == null || files.length == 0) {
            return;
        }
        for (File f : files) {
            //如果是文件夹,就继续往下层找
            if (f.isDirectory()) {
                showFiles(f);
            } else {
                System.out.println(f.getAbsoluteFile() + "\tSize:" + f.length() / (1024 * 1024) + "MB");
            }
        }
    }

}

3、相对路径和绝对路径

绝对路径:从盘符开始,是一个完整的路径 例如: E://a/1.txt

相对路径:相对于项目目录的路径

4、IO流

Input:输入,输入(读)到JAVA程序

Ouput:输出,输出(写)到别的地方,例如写到系统中

分类

按照流的方向:输入流、输出流

按照流动的数据类型:字符流(文字)、字节流(其他)

字符流和字节流

字节流操作的基本单元为字节byte;字符流操作的基本单元为Unicode码元(char)。

字节流默认不使用缓冲区;字符流使用缓冲区。

字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。

用字节流读取文字,可能会出现某一个中文,占3个字节,被多次读取,就识别不出来的情况,所以要用转换流,把字节转换成字符

用字符流操作文字,需要使用flush方法刷新缓存。close方法中,也会先执行flush

顶级父类

输出流

输入流

字节流

InputStream

OuputStream

字符流

Reader

Writer

4.1、字节流

一切皆字节:计算机中的任何数据,都是以二进制的形式存储的,8个bit就是一个字节。在数据传输时,也都是以二进制存储的。

后续学习的任何流,在传输时,底层都是二进制(包括字符流)

4.1.1、OutputStream 抽象类

变量和类型

方法

描述

void

close()

关闭此输出流并释放与此流关联的所有系统资源。关闭要尽可能早,且用完一定要关闭

void

flush()

刷新此输出流并强制写出任何缓冲的输出字节。

static OutputStream

nullOutputStream()

返回一个新的 OutputStream ,它丢弃所有字节。

void

write​(byte[] b)

将 b.length字节从指定的字节数组写入此输出流。

void

write​(byte[] b, int off, int len)

将从off下标开始,写出len个字节

abstract void

write​(int b)

将指定的字节写入此输出流。

FileOutputStream 实现类,通过这个流,可以向指定的文件,输出内容

构造器

描述

FileOutputStream​(File file)

创建文件输出流以写入由指定的 File对象表示的文件。

FileOutputStream​(FileDescriptor fdObj)

创建要写入指定文件描述符的文件输出流,该文件描述符表示与文件系统中实际文件的现有连接。

FileOutputStream​(File file, boolean append)

创建文件输出流以写入由指定的 File对象表示的文件。append为true,就是接着原来的往后写,为false就是把文件内容清空,重新写

FileOutputStream​(String name)

创建文件输出流以写入具有指定名称的文件。

FileOutputStream​(String name, boolean append)

创建文件输出流以写入具有指定名称的文件。

FileOutputStream使用构造方法指定一个File或文件路径构造一个流,如果文件不存在,会自动创建文件,除非权限不够

一个流创建之后,不管有没有append,都可以write多次,write的位置会接着上一次write结束的位置,直到关闭

4.1.2、InputputStream 抽象类

变量和类型

方法

描述

int

available()

返回可以从此输入流中无阻塞地读取(或跳过)的字节数的估计值,可以是0,或者在检测到流结束时为0。

void

close()

关闭此输入流并释放与该流关联的所有系统资源。

void

mark​(int readlimit)

标记此输入流中的当前位置。

boolean

markSupported()

测试此输入流是否支持 mark和 reset方法。

static InputStream

nullInputStream()

返回一个不读取任何字节的新 InputStream 。

abstract int

read()

从输入流中读取下1个数据字节。 值字节返回int ,范围为0至255 。 如果由于到达流末尾而没有可用字节,则返回值-1 。 此方法将阻塞,直到输入数据可用,检测到流的末尾或抛出异常。

int

read​(byte[] b)

从输入流中读取一些字节数并将它们赋值到缓冲区数组 b 。返回实际读取的字节数。如果b的长度为零,则不读取任何字节,并返回0 ; 否则,尝试读取至少一个字节。 如果由于流位于文件末尾而没有可用字节,则返回值-1 ; 否则,至少读取一个字节并存储到b 。

int

read​(byte[] b, int off, int len)

从输入流 len最多 len字节的数据读入一个字节数组。

byte[]

readAllBytes()

从输入流中读取所有剩余字节。

int

readNBytes​(byte[] b, int off, int len)

从输入流中读取请求的字节数到给定的字节数组中。

byte[]

readNBytes​(int len)

从输入流中读取指定的字节数。

void

reset()

将此流重新定位到上次在此输入流上调用 mark方法时的位置。

long

skip​(long n)

跳过并丢弃此输入流中的 n字节数据。

long

transferTo​(OutputStream out)

从该输入流中读取所有字节,并按读取顺序将字节写入给定的输出流。

FileInputStream 实现类

构造器

描述

FileInputStream​(File file)

通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的 File对象 file命名。

FileInputStream​(FileDescriptor fdObj)

使用文件描述符 fdObj创建 FileInputStream ,该文件描述符表示与文件系统中实际文件的现有连接。

FileInputStream​(String name)

通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的路径名 name命名。

FileInputStream如果没有读取到文件,不会自动创建

一个流在read之后,如果没有close,可以接着read,read的位置接着上一次read的末尾

尽量使用byte[]来读取字节,而不是单读取一个byte多次,read次数越少越好。这样速度才会快

public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream("E:/1.txt");
    byte[] bytes = "1234567890".getBytes();
    fos.write(bytes);
    fos.close();
    FileInputStream fis = new FileInputStream("E:/1.txt");
    byte[] byte1 = new byte[2];
    int len = 0;
    while (len != -1) {
        System.out.println(new String(byte1,0,len));
        len = fis.read(byte1);
    }
    fis.close();
    System.out.println(Arrays.toString(byte1));
}

4.2、字符流

4.2.1、Writer抽象类

变量和类型

方法

描述

Writer

append​(char c)

将指定的字符追加到此writer。

Writer

append​(CharSequence csq)

将指定的字符序列追加到此writer。

Writer

append​(CharSequence csq, int start, int end)

将指定字符序列的子序列追加到此writer。

abstract void

close()

关闭流,先冲洗它。

abstract void

flush()

刷新流。

static Writer

nullWriter()

返回一个新的 Writer ,它丢弃所有字符。

void

write​(char[] cbuf)

写一个字符数组。

abstract void

write​(char[] cbuf, int off, int len)

写一个字符数组的一部分。

void

write​(int c)

写一个字符。

void

write​(String str)

写一个字符串。

void

write​(String str, int off, int len)

写一个字符串的一部分。

FileWriter 实现类

构造器

描述

FileWriter​(File file)

给 File写一个 FileWriter ,使用平台的 default charset

FileWriter​(FileDescriptor fd)

构造一个 FileWriter给出的文件描述符,使用该平台的 default charset

FileWriter​(File file, boolean append)

在给出要写入的 FileWriter下构造 File ,并使用平台的 default charset构造一个布尔值,指示是否附加写入的数据。

FileWriter​(File file, Charset charset)

构造一个FileWriter给予File编写和charset

FileWriter​(File file, Charset charset, boolean append)

构造FileWriter给出File写入, charset和一个布尔值,指示是否附加写入的数据。

FileWriter​(String fileName)

构造一个 FileWriter给出文件名,使用平台的 default charset

FileWriter​(String fileName, boolean append)

使用平台的 default charset构造一个 FileWriter给定一个文件名和一个布尔值,指示是否附加写入的数据。

FileWriter​(String fileName, Charset charset)

构造一个FileWriter给出文件名和charset

FileWriter​(String fileName, Charset charset, boolean append)

构造一个FileWriter给定一个文件名, charset和一个布尔值,指示是否附加写入的数据。

4.2.2、Reader抽象类

变量和类型

方法

描述

abstract void

close()

关闭流并释放与其关联的所有系统资源。

void

mark​(int readAheadLimit)

标记流中的当前位置。

boolean

markSupported()

判断此流是否支持mark()操作。

static Reader

nullReader()

返回不读取任何字符的新 Reader 。

int

read()

读一个字符。

int

read​(char[] cbuf)

将字符读入数组。

abstract int

read​(char[] cbuf, int off, int len)

将字符读入数组的一部分。

int

read​(CharBuffer target)

尝试将字符读入指定的字符缓冲区。

boolean

ready()

判断此流是否可以读取。

void

reset()

重置流。

long

skip​(long n)

跳过字符。

long

transferTo​(Writer out)

读取此阅读器中的所有字符,并按照读取的顺序将字符写入给定的编写器。

FileReader 实现类

构造器

描述

FileReader​(File file)

使用平台 FileReader ,在 File读取时创建一个新的 FileReader

FileReader​(FileDescriptor fd)

使用平台 default charset创建一个新的 FileReader ,给定 FileDescriptor进行读取。

FileReader​(File file, Charset charset)

创建一个新的FileReader ,给出File读取和charset

FileReader​(String fileName)

使用平台 default charset创建一个新的 FileReader ,给定要读取的文件的 名称

FileReader​(String fileName, Charset charset)

给定要读取的文件的名称和FileReader ,创建一个新的FileReader

public static void main(String[] args) throws IOException {
    FileWriter fw = new FileWriter("E:/b.txt");
    fw.write("龘龘龘龘龖龖龘惡惡辶辶");
    fw.append("11111").append("22222").append("33333");
    fw.flush();
    fw.close();
    FileReader fr = new FileReader("E:/b.txt");
    char[] chars = new char[2];
    int lenth = 0;
    while (lenth != -1) {
        System.out.println(new String(chars, 0, lenth));
        lenth = fr.read(chars);
    }
}

BufferedReader和FileReader区别

BufferedReader(FileReader("filename"))将FileReader包装后,再使用read(char[] chbf)读取,可以将文件内容装入缓存。而FileReader则会频繁使用底层IO,造成阻塞其他需要访问IO的操作,所以读取文件BufferedReader比FileReader更高效。

BufferedReader提供了readLine方法。可以读取一整行为一个String

4.3、转换流。将字节流装饰为字符流:使用装饰者设计模式

InputStreamReader

构造器

描述

InputStreamReader​(InputStream in)

创建一个使用默认字符集的InputStreamReader。

InputStreamReader​(InputStream in, String charsetName)

创建一个使用指定charset的InputStreamReader。

InputStreamReader​(InputStream in, Charset cs)

创建一个使用给定charset的InputStreamReader。

InputStreamReader​(InputStream in, CharsetDecoder dec)

创建一个使用给定charset解码器的InputStreamReader。

OutputStreamReader

public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("E:/b.txt");
    InputStreamReader isr = new InputStreamReader(fis, "utf-8");
    while (true) {
        int word =  isr.read();
        if (word == -1) {
            break;
        }
        System.out.println((char)word);
    }

    FileOutputStream fos = new FileOutputStream("E:/b.txt");
    OutputStreamWriter osw = new OutputStreamWriter(fos);
    osw.write("床前明月光");
    osw.flush();
    osw.close();
    
}

4.4、字符输出打印流、缓冲读取流

PrintStream

PrintWriter 也可以转换字节流进行输出

public static void main(String[] args) throws FileNotFoundException {
    PrintStream ps = new PrintStream("E:/c2.txt");
    ps.println("11111");
    ps.println("22222");
    ps.println("33333");
    ps.close();

    PrintWriter pw = new PrintWriter("E:/c1.txt");
    pw.println("55555");
    pw.println("55555");
    pw.println("55555");
    pw.flush();
    pw.close();

    FileOutputStream fos = new FileOutputStream("E:/b.txt");
    PrintWriter pw1 = new PrintWriter(fos);
    pw1.println("bbbbbbbbb");
    pw1.flush();
    pw1.close(); 
}

BufferedReader

可以将FileReader转为BufferedReader,进行读取行

读取行readLine读完时,会返回null

public static void main(String[] args) throws IOException {
    FileReader fr = new FileReader("E:/c2.txt");
    BufferedReader br = new BufferedReader(fr);
    while (true) {
        String str = br.readLine();
        if (str == null) {
            break;
        }
        System.out.println(str);
    }
}

4.5、输出错误日志

public static void main(String[] args) throws FileNotFoundException {
    String s = null;
    try {
        s.toString();
    } catch (Exception e) {
        PrintWriter pw = new PrintWriter("E:/bugs.txt");
        e.printStackTrace(pw);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        pw.println("报错时间:" + sdf.format(new Date()));
        pw.close();
    }
}

5、Properties

本质上是一个HashTable,操作与HashMap一致

变量和类型

方法

描述

String

getProperty​(String key)

在此属性列表中搜索具有指定键的属性。

String

getProperty​(String key, String defaultValue)

在此属性列表中搜索具有指定键的属性。

void

list​(PrintStream out)

将此属性列表打印到指定的输出流。

void

list​(PrintWriter out)

将此属性列表打印到指定的输出流。

void

load​(InputStream inStream)

从输入字节流中读取属性列表(键和元素对)。

void

load​(Reader reader)

以简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

void

loadFromXML​(InputStream in)

将指定输入流上的XML文档表示的所有属性加载到此属性表中。

Enumeration<?>

propertyNames()

返回此属性列表中所有键的枚举,如果尚未从主属性列表中找到相同名称的键,则包括默认属性列表中的不同键。

void

save​(OutputStream out, String comments)

已过时。现在用store

如果在保存属性列表时发生I / O错误,则此方法不会抛出IOException。

Object

setProperty​(String key, String value)

调用 Hashtable方法 put 。

void

store​(OutputStream out, String comments)

将此 Properties表中的此属性列表(键和元素对)以适合使用 load(InputStream)方法加载到 Properties表的格式写入输出流。

void

store​(Writer writer, String comments)

将此 Properties表中的此属性列表(键和元素对)以适合使用 load(Reader)方法的格式写入输出字符流。

void

storeToXML​(OutputStream os, String comment)

发出表示此表中包含的所有属性的XML文档。

void

storeToXML​(OutputStream os, String comment, String encoding)

使用指定的编码发出表示此表中包含的所有属性的XML文档。

void

storeToXML​(OutputStream os, String comment, Charset charset)

使用指定的编码发出表示此表中包含的所有属性的XML文档。

Set<String>

stringPropertyNames()

从此属性列表返回一组不可修改的键,其中键及其对应的值是字符串,如果尚未从主属性列表中找到相同名称的键,则包括默认属性列表中的不同键。

public static void main(String[] args) throws IOException {
    Properties properties = new Properties();
    properties.put("userName", "11111");
    properties.put("password", "666666");
    FileWriter fw = new FileWriter("E:/userInfo.properties");
    properties.store(fw,"啊啊啊啊龘龘");
    fw.flush();
    fw.close();

    Properties p2 = new Properties();
    FileReader r = new FileReader("E:/userInfo.properties");
    p2.load(r);
    System.out.println(p2.getProperty("userName"));
    System.out.println(p2.get("username"));
    System.out.println(p2.get("password"));
    r.close();
}

6、序列化与反序列化

序列化:把对象存到文件

反序列化:把文件转为对象

要序列化的类型,需要实现Serializable接口。要序列化的类型中的属性如果是一个类,也要实现Serializable接口

存入的如果是集合,拿出来也要用对应的集合装

public class Test9 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //写入数据
        /*LinkedList<Book> list = new LinkedList<>();
        Book book1 = new Book("第一本书", "语文书");
        Book book2 = new Book("第二本书", "数学书");
        Book book3 = new Book("第三本书", "英语书");
        list.add(book1);
        list.add(book2);
        list.add(book3);

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/books.txt"));
        oos.writeObject(list);
        oos.close();*/

        //读取数据
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/books.txt"));
        LinkedList<Book> bookList = (LinkedList<Book>) ois.readObject();
        System.out.println(bookList.toString());
    }

    static class Book implements Serializable {
        private String name;
        private String info;

        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", info='" + info + '\'' +
                    '}';
        }

        public Book() {
        }

        public Book(String name, String info) {
            this.name = name;
            this.info = info;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getInfo() {
            return info;
        }

        public void setInfo(String info) {
            this.info = info;
        }
    }
}

6.1、序列化中忽略不想序列化的属性

6.1.1、transient关键字

在实现序列化接口的类的属性前 加上 transient关键字 priavate transient String name。该属性就会在序列化的时候被忽略

6.1.2、static关键字

用static修饰的字段,也不会被序列化,但是这个值因为是static的,会在JVM中和这个字段所属的类进行绑定,如果这个属性被赋值过,且JVM没有关闭,创建类时,一样会读取到这个属性,且是唯一的。

public class Test9 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //写入数据
        LinkedList<Book> list = new LinkedList<>();
        Book book1 = new Book("第一本书", "语文书");
        Book book2 = new Book("第二本书", "数学书");
        Book book3 = new Book("第三本书", "英语书");
        list.add(book1);
        list.add(book2);
        list.add(book3);

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/books.txt"));
        oos.writeObject(list);
        oos.close();

        //读取数据
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/books.txt"));
        Collection<Object> bookList = Collections.singleton(ois.readObject());
        System.out.println(bookList.toString());
    }

    static class Book implements Serializable {
        private transient String name;
        private static String info;

        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", info='" + info + '\'' +
                    '}';
        }

        public Book() {
        }

        public Book(String name, String info) {
            this.name = name;
            this.info = info;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getInfo() {
            return info;
        }

        public void setInfo(String info) {
            this.info = info;
        }
    }
}

输出结果:
[[Book{name='null', info='英语书'}, Book{name='null', info='英语书'}, Book{name='null', info='英语书'}]]

6.1.3、默认方法实现序列化

private void writeObject(ObjectOutputStream out){}

private void readObject(ObjectInputStream in){}

在要序列化的类中,手动添加 写入序列化方法或者读取序列化方法,也能达到把想序列化的属性,进行序列化的效果,不受transient的影响

该方法必须是 private void的

但是static的原则,如上,依然存在

package com.syp.file.test;

import java.io.*;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;

/**
 * @author suyiping
 * @create 2021-06-24 21:25
 */
public class Test9 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //写入数据
        LinkedList<Book> list = new LinkedList<>();
        Book book1 = new Book("第一本书", "语文书", 10);
        Book book2 = new Book("第二本书", "数学书", 11);
        Book book3 = new Book("第三本书", "英语书", 12);
        list.add(book1);
        list.add(book2);
        list.add(book3);

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/books.txt"));
        oos.writeObject(list);
        oos.close();

        //读取数据
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/books.txt"));
        Collection<Object> bookList = Collections.singleton(ois.readObject());
        System.out.println(bookList.toString());
    }

    static class Book implements Serializable {
        private transient String name;
        private static String info;
        private Integer age;
        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", info='" + info + '\'' +
                    ", age=" + age +
                    '}';
        }

        private void writeObject(ObjectOutputStream out) throws IOException {
            out.writeObject(name);
//            out.writeObject(age);
        }
        private  void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
            name = (String) in.readObject();
//            age = (Integer) in.readObject();
        }
        public Book() {
        }

        public Book(String name, String info, int age) {
            this.name = name;
            this.info = info;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getInfo() {
            return info;
        }

        public void setInfo(String info) {
            this.info = info;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

输出结果 
[[Book{name='第一本书', info='英语书', age=null}, Book{name='第二本书', info='英语书', age=null}, Book{name='第三本书', info='英语书', age=null}]]

6.1.4、Externalizable接口,实现序列化

与6.1.3中使用方法类似,作为了解就行,不常用

package com.syp.file.test;

import java.io.*;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;

/**
 * @author suyiping
 * @create 2021-06-24 21:25
 */
public class Test9 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //写入数据
        LinkedList<Book> list = new LinkedList<>();
        Book book1 = new Book("第一本书", "语文书", 10);
        Book book2 = new Book("第二本书", "数学书", 11);
        Book book3 = new Book("第三本书", "英语书", 12);
        list.add(book1);
        list.add(book2);
        list.add(book3);

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/books.txt"));
        oos.writeObject(list);
        oos.close();

        //读取数据
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/books.txt"));
        Collection<Object> bookList = Collections.singleton(ois.readObject());
        System.out.println(bookList.toString());
    }

    static class Book implements Externalizable {
        private transient String name;
        private static String info;
        private Integer age;
        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", info='" + info + '\'' +
                    ", age=" + age +
                    '}';
        }

        public Book() {
        }

        public Book(String name, String info, int age) {
            this.name = name;
            this.info = info;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getInfo() {
            return info;
        }

        public void setInfo(String info) {
            this.info = info;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeObject(name);
        }

        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            name = (String) in.readObject();
        }
    }
}

6.1.5、Serializable接口与Externalizable

区别

Serializable

Externalizable

实现复杂度

实现简单

实现复杂

执行效率

所有对象统一保存,速度相对慢

部分保存,速度相对快

保存信息

全部保存,保存时空间相对使用较大

部分保存,空间使用相对较小

使用频率

低,面试有可能问到

7、try-with-resources

JDK1.7之前

public static void main(String[] args) {
    FileReader fr =null;
    try  {
         fr = new FileReader("E:/1.txt");
        int c = fr.read();
        if (c != -1) {
            System.out.println((char) c);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

JDK1.7时 在try()中可以声明一个类,该类必须是实现了Closeable接口的,结束try后,会自动close

public static void main(String[] args) throws FileNotFoundException {
    try (FileReader fr = new FileReader("E:/1.txt")) {
        int c = fr.read();
        if (c != -1) {
            System.out.println((char) c);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

JDK9 用分号隔开。可以放入多个类

public static void main(String[] args) throws FileNotFoundException {
    FileReader fr = new FileReader("E:/1.txt");
    FileInputStream fis = new FileInputStream("E:/1.txt");
    try (fr; PrintWriter pw =new PrintWriter("E:/1.txt");fis) {
        int c = fr.read();
        if (c != -1) {
            System.out.println((char) c);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值