08-java之io流基础

io流学习流程

说白了,本节的目的就是对 文件增删改查,先说一下学习顺序吧

  1. 定位文件
    • File类可以定位文件:可以进行删除文件内容,读取文件本身信息等操作,但是不能读写文件内容
  2. 字符集
    • 想要读取文件中的数据,就必须知道数据的底层形式(字节,字符)
  3. 读写文件内容
    • IO流可以对硬盘中的文件进行读写

File类

File类学习流程

  1. 如何创建一个File类
  2. 使用File类,创建、删除、判断、获取
  3. 遍历文件夹
  4. 删除文件夹

image-20230208013130427

File类概述和构造方法

  • File类介绍

    • 它是文件和目录路径名的抽象表示
    • 文件和目录是可以通过File封装成对象的
    • 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已.它可以是存在的,也可以是不存在的.将来是要通过具体的操作把这个路径的内容转换为具体存在的
  • File类的构造方法

方法名 说明
File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
  • 示例代码
public class FileDemo01 {
    
    
    public static void main(String[] args) {
    
    
        //File(String pathname): 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
        File f1 = new File("E:\\iotest\\java.txt");
        System.out.println(f1);

        //File(String parent, String child): 从父路径名字符串和子路径名字符串创建新的 File实例
        File f2 = new File("E:\\iotest","java.txt");
        System.out.println(f2);

        //File(File parent, String child): 从父抽象路径名和子路径名字符串创建新的 File实例
        File f3 = new File("E:\\iotest");
        File f4 = new File(f3,"java.txt");
        System.out.println(f4);
    }
}

绝对路径和相对路径

  • 绝对路径
    是一个完整的路径,从盘符开始
  • 相对路径
    是一个简化的路径,相对当前项目下的路径
  • 示例代码
public class FileDemo02 {
    
    
    public static void main(String[] args) {
    
    
        // 是一个完整的路径,从盘符开始
        File file1 = new File("D:\\iotest\\a.txt");

        // 是一个简化的路径,从当前项目根目录开始
        File file2 = new File("a.txt");
        File file3 = new File("模块名\\a.txt");
    }
}

File类创建功能-通过File创建文件

  • 方法分类
方法名 说明
public boolean createNewFile() 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir() 创建由此抽象路径名命名的目录
public boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
  • 示例代码
import java.io.File;
import java.io.IOException;

public class FileDemo02 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //需求1:我要在E:\\iotest目录下创建一个文件java.txt
        File f1 = new File("E:\\iotest\\java.txt");
        File parentFile = f1.getParentFile(); // E:\iotest 就是获取上一个文件夹/文件的内容
        System.out.println("创建文件夹,解决因为文件不存在发生的异常:" + parentFile.mkdirs());
        System.out.println("创建一个文件:" + f1.createNewFile());  //   //注意点:文件所在的文件夹必须要存在.
        System.out.println("--------");

        //需求2:我要在E:\\iotest目录下创建一个目录JavaSE,不能创建多级
        File f2 = new File("E:\\iotest\\JavaSE");
        System.out.println(f2.mkdir());
        System.out.println("--------");

        //需求3:我要在E:\\iotest目录下创建一个多级目录JavaWEB\\HTML
        File f3 = new File("E:\\iotest\\JavaWEB\\HTML");
        System.out.println(f3.mkdirs());
        System.out.println("--------");

        // 获取当前模块路径
        String currentPath=System.getProperty("user.dir");
      
        //需求4:我要在当前模块目录下创建一个多级目录JavaWEB\\HTML
        File f4 = new File("iotest4\\java.txt");
        if( f4.getParentFile() != null &&  f4.getParentFile().mkdirs()){
    
    
            System.out.println("成功创建文件夹");
        }
        System.out.println("创建一个文件:" + f4.createNewFile());
    }
}

File类删除功能

Java中File.delete删除当前文件或者文件夹,java删除的文件,将会直接删除,不会进入回收站。
如果删除的是文件夹,则该文件必须为空,如果要删除一个非空的文件夹,则需要首先删除该文件夹下面每个文件和文件夹,才可以删除。

  • 方法分类
方法名 说明
public boolean delete() delete方法只能删除文件和空文件夹
  • 示例代码
public class FileDemo03 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        // 获取当前模块路径
        String currentPath=System.getProperty("user.dir");
        // 删除文件
        File f1 = new File("iotest\\java.txt");
        f1.delete();
        // 删除目录
        File f2 = new File("iotest");
        f2.delete();
    }
}

File类判断和获取功能

  • 判断功能
方法名 说明
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
  • 获取功能
方法名 说明
public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径名字符串
public String getName() 返回由此抽象路径名表示的文件或目录的名称
public File[] listFiles() 返回此抽象路径名表示的目录中的文件和目录的File对象数组
  • 示例代码
public class FileDemo04 {
    
    
    public static void main(String[] args) {
    
    
        //创建一个File对象
        File f = new File("myFile\\java.txt");

//        public boolean isDirectory():测试此抽象路径名表示的File是否为目录
//        public boolean isFile():测试此抽象路径名表示的File是否为文件
//        public boolean exists():测试此抽象路径名表示的File是否存在
        System.out.println(f.isDirectory());
        System.out.println(f.isFile());
        System.out.println(f.exists());

//        public String getAbsolutePath():返回此抽象路径名的绝对路径名字符串
//        public String getPath():将此抽象路径名转换为路径名字符串
//        public String getName():返回由此抽象路径名表示的文件或目录的名称
        System.out.println(f.getAbsolutePath());
        System.out.println(f.getPath());
        System.out.println(f.getName());
        System.out.println("--------");

//        public File[] listFiles():返回此抽象路径名表示的目录中的文件和目录的File对象数组
        File f2 = new File("E:\\iotest");
        File[] fileArray = f2.listFiles();
        for(File file : fileArray) {
    
    
//            System.out.println(file);
//            System.out.println(file.getName());
            if(file.isFile()) {
    
    
                System.out.println(file.getName());
            }
        }
    }
}

File类练习-遍历文件夹下所有文件-控制台以树形展示

  • 案例需求
    遍历文件夹下所有文件
    打印格式如下:
filemodule
|_aaa
|__a.txt
|___111.txt					0MB
|__b.txt					0MB
  • 代码实现
import java.io.File;

class FileSystem {
    
    
    public static void main(String[] args) {
    
    
        File f = new File("filemodule");// 指定文件位置
        System.out.println(f.getName());// 打印在这个文件下地文件夹;
        tree(f, 1);// 方法!进入子文件夹中 并打印子文件名
    }

    private static void tree(File f, int level) {
    
    
        File[] childs = f.listFiles();// 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中地文件
        for (int i = 0; i < childs.length; i++) {
    
    
            // 打印前缀
            for (int j = 0; j < level; j++) {
    
    
                if (j == 0) {
    
    
                    System.out.print("|_");
                } else {
    
    
                    System.out.print("_");
                }
            }
            if (childs[i].isDirectory()) {
    
     //
                System.out.println(childs[i].getName());// 打印子文件地名字
                tree(childs[i], level + 1);
            } else {
    
    
                System.out.println(childs[i].getName() + "\t\t\t\t\t" + childs[i].length() / 1024 / 1024 + "MB");// 如果是文件把大小也打印出来
            }

        }

    }
}

File类练习-删除文件夹所有内容

  • 案例需求
    删除一个多级文件夹
  • 实现步骤
    • 定义一个方法,接收一个File对象
    • 遍历这个File对象,获取它下边的每个文件和文件夹对象
    • 判断当前遍历到的File对象是文件还是文件夹
    • 如果是文件夹,递归调用自己,将当前遍历到的File对象当做参数传递
    • 将得到的文件或者空目录删除
    • 参数传递过来的文件夹File对象已经处理完成,最后直接删除这个空文件夹
  • 代码实现
import java.io.File;

public class Test2 {
    
    
    public static void main(String[] args) {
    
    
        /**
         * delete方法只能删除文件和空文件夹
         * 如果现在要删除一个有内容的文件夹
         *      先删掉这个文件夹里面所有的内容
         *      最后再删除这个文件夹
         */

        File src = new File("iotest2");
        remove(src);
    }

    /**
     * 删除指定文件夹下的全部内容
     *
     * @param file
     */
    public static void remove(File file) {
    
    
        File[] files = file.listFiles();//将file子目录及子文件放进文件数组
        if (files != null) {
    
    //如果包含文件进行删除操作
            for (int i = 0; i < files.length; i++) {
    
    
                if (files[i].isDirectory()) {
    
    //通过递归方法删除子目录的文件
                    remove(files[i]);
                }
                files[i].delete();//删除子目录/子文件
            }
            file.delete(); // 删除传过来的目录
        }
    }
}

字符集

字符集相关概念

我们是怎么把文字存储到计算机的

  • 我们把文字转换成十进制的表现方式(比如“a”相当于97),然后转换成二进制,然后就可以存储到计算机。

什么是字符集?什么叫字符编码

字符集(Character set)是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等

  • 字符集:规定了字符和字符码之间的对应关系。 可以将字符集理解成一个很大的表格,它列出了所有字符和二进制的对应关系,计算机显示文字或者存储文字,就是一个查表的过程。
  • 字符编码:规定了一个字符码在计算机中如何存储。

常用字符集

  • ASCII字符集(American Standard Code for Information Interchange,美国信息交换标准代码)

    • 是最早产生的编码规范,包括数字、英文、符号
    • 一个字节存储一个字符,也就是8位,总共可以表示128个字符信息(2^8=256,不包括负数)
  • GBK(即“国标”“扩展”汉语拼音的第一个字母) 字符集:全称《汉字内码扩展规范》

    • window系统默认的码表。兼容ASCII码表,包括中日韩
    • 一个中文以两个字节存储,英文1个字节
  • Unicode字符集(又叫万国码、统一码):是计算机科学领域里的一项业界字符编码规范
    • Unicode包含了全世界所有的字符,兼容ASCII 。Unicode最多可以保存4个字节容量的字符。也就是说,要区分每个字符,每个字符的地址需要4个字节。这是十分浪费存储空间的,于是,程序员就设计了几种字符编码方式,比如:UTF-8,UTF-16,UTF-32。最广为程序员使用的就是UTF-8,UTF-8是一种变长字符编码,注意:UTF-8不是编码规范,而是编码方式。
      • utf-8:一个中文以3个字节存储,英文1个字节

小结

  • 英文和数字在任何国家的字符集中都占一个字节(在任何国家的编码中都不会乱码)
  • GBK中一个中文字符2个字节
  • UTF-8中一个中文字符3个字节
  • 编码前的字符集和编码后的字符集必须一致,否则乱码
  • 中文的字节存储方式
    • 用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
    • 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

字符集的编码、解码操作

代码如下:

class FileSystem {
    
    
    public static void main(String[] args) throws UnsupportedEncodingException {
    
    
        String str = "a1爱";

        byte[] gbks1 = str.getBytes();
        System.out.println(gbks1.length);
        System.out.println("以当前默认字符集编码:" + Arrays.toString(gbks1));
        System.out.println("以当前默认字符集解码:" + new String(gbks1));

        byte[] gbks2 = str.getBytes("GBK");
        System.out.println(gbks2.length);
        System.out.println("指定以GBK编码:" + Arrays.toString(gbks2));
        System.out.println("以当前默认字符集解码GBK编码的数据:" +  new String(gbks2));
        System.out.println("指定以GBK解码:" +  new String(gbks2,"GBK"));
        
    }
}

输出如下

5
以当前默认字符集编码:[97, 49, -25, -120, -79]
以当前默认字符集解码:a1爱
4
指定以GBK编码:[97, 49, -80, -82]
以当前默认字符集解码GBK编码的数据:a1��
指定以GBK解码:a1爱

汉字的存储和解析过程

image-20230209232022296

IO流

IO流的使用流程

  1. 创建输入/输出流
  2. 读/写 操作
  3. 关闭输入/输出流

IO流的概念与作用

I/O是Input/Output的缩写, 用于处理设备之间的数据传输。如读/写文件,网络通讯等。

流是一种抽象概念,它代表了数据的无结构化传递。

Java程序中,对于数据的输入/输出操作以”流(stream)” 的方式进行,所以叫io流。java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。常见的应用: 文件复制; 文件上传; 文件下载

IO流的分类

按照数据的流向(方向)

  • 输入流:读数据,是数据从硬盘文件读入到内存的过程 =》 硬盘->内容
  • 输出流:写数据,是内存程序的数据从内存写出到硬盘文件的过程=》内存->硬盘

按照数据类型(单位)

  • 字节流:以字节为单位,可以读写所有数据
  • 字符流:以字符为单位

使用场景

如果操作的是纯文本,比如json文件,txt文件,优先使用字符流

  • 怎么判断是纯文本呢? 能用记事本打开并且能看懂的就是纯文本

如果是图片、视频、音频等二进制文件,优先使用字节流

如果不确认文件类型,优先使用字节流,字节流是万能的流

IO流体系结构图

字节流(byte) 字符流(char)
分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
操作文件 FileInputStream FileOutputStream FileReader FileWriter
操作数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象操作流 ObjectInputStream ObjectOutputStream
打印流 PrintStream PrintWriter

其中,转换流都是字节流转字符流。

  • OutputStreamWriter : 字节输出流 -> 字符输出流;
  • InputStreamReader : 字节输入流 -> 字符输入流

对象操作流也叫序列化流

字节流/字符流基础操作

字节输入流InputStream主要方法:

  • read() :从此输入流中读取一个数据字节。

  • read(byte[] b) :从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。

  • read(byte[] b, int off, int len) :从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。

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

字节输出流OutputStream主要方法:

  • write(byte[] b) :将 b.length 个字节从指定 byte 数组写入此文件输出流中。
  • write(byte[] b, int off, int len) :将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
  • write(int b) :将指定字节写入此文件输出流。
  • flush() :刷新流,之后还可以继续写数据
  • close() :关闭此输入流并释放与该流关联的所有系统资源。

字符输入流Reader主要方法:

  • read():读取单个字符。
  • read(char[] cbuf) :将字符读入数组。
  • read(char[] cbuf, int off, int len) : 将字符读入数组的某一部分。
  • read(CharBuffer target) :试图将字符读入指定的字符缓冲区。
  • close() :关闭此流,但要先刷新它。

字符输出流Writer主要方法:

  • write(char[] cbuf) :写入字符数组。

  • write(char[] cbuf, int off, int len) :写入字符数组的某一部分。

  • write(int c) :写入单个字符。

  • write(String str) :写入字符串。

  • write(String str, int off, int len) :写入字符串的某一部分。

  • flush() :刷新流,之后还可以继续写数据

  • close() :关闭此流,但再次之前刷新它。 一旦流已关闭,进一步的write()或flush()调用将导致抛出IOException。 关闭以前关闭的流无效。

另外,字符缓冲流还有两个独特的方法:

  • BufferedWriter类newLine() :写入一个行分隔符。这个方法会自动适配所在系统的行分隔符。
  • BufferedReader类readLine() :读取一个文本行。

注意:输出流必须刷新才能写入,当然也可以直接调用close() ,他里面包含了flush,但是使用close()关闭流后就不能在使用了

如上,常用方法

  • 输入流都有read方法

  • 输出流都有write,flush方法

字节输入流读文件

代码如下:

public class ByteInputStreamTest1 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        /**
         * 字节输入流的使用方式
         */
        // 1、创建输入流 => InputStream
        InputStream fileInputStream = new FileInputStream("aa.txt"); // abc123测试
        // 2、读文件

        // read() :从此输入流中读取一个数据字节。
        int read = fileInputStream.read();
        System.out.println(read); // 97
        System.out.println((char) read); // a

        byte[] buffered = new byte[3];
        // read(byte[] b) :从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
        //int read1 = fileInputStream.read(buffered);
        //System.out.println(read1); // 读取的字符数量 => 3
        //System.out.println(Arrays.toString(buffered)); // [98, 99, 49]
        //System.out.println(new String(buffered)); // bc1

        // read(byte[] b, int off, int len) :从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
        int read2 = fileInputStream.read(buffered, 0, 2);
        System.out.println(read2); // 2
        System.out.println(Arrays.toString(buffered)); // [98, 99, 0]
        System.out.println(new String(buffered)); // bc 

        // 如果没有读取到呢吗返回-1

        // 3、关闭资源
        fileInputStream.close();
    }
}

字符输入流读文件

  • 介绍
    Reader: 用于读取字符流的抽象父类
    FileReader: 用于读取字符流的常用子类
  • 构造方法
方法名 说明
FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader
FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader
  • 成员方法
方法名 说明
int read() 一次读一个字符数据
int read(char[] cbuf) 一次读一个字符数组数据
  • 代码演示
import java.io.FileReader;
import java.io.IOException;

public class InputStreamReaderDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileReader fr = new FileReader("myCharStream\\b.txt");
        
        //int read():一次读一个字符数据
        int ch;
        while ((ch = fr.read()) != -1) {
    
    
            System.out.print((char) ch);
        }
        
        // int read(char[] cbuf):一次读一个字符数组数据
        char[] chs = new char[1024];
        int len;
        while ((len = fr.read(chs)) != -1) {
    
    
            System.out.print(new String(chs, 0, len));
        }
        // 释放资源       
         fr.close();  
    }
}

字节输出流写数据

  • 使用字节输出流写数据的步骤

    • 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
    • 调用字节输出流对象的写数据方法
    • 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
  • 写数据的方法分类

方法名 说明
void write(int b) 将指定的字节写入此文件输出流 一次写一个字节数据
void write(byte[] b) 将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组数据
void write(byte[] b, int off, int len) 将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一次写一个字节数组的部分数据
  • 示例代码
package ioreview.bytestream;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo02 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        // 1、创建输出流
        //FileOutputStream(String name):创建文件输出流以指定的名称写入文件
        //FileOutputStream fos = new FileOutputStream("fos.txt");
        // FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件
        FileOutputStream fos = new FileOutputStream(new File("fos.txt"));

        // 2、写入数据
        // void write(int b):将指定的字节写入此文件输出流
        fos.write(97);
        fos.write(98);
        fos.write(99);

        //void write(byte[] b):将 b.length字节从指定的字节数组写入此文件输出流
        byte[] bys = {
    
    97, 98, 99};
        fos.write(bys);

        //byte[] getBytes():返回字符串对应的字节数组
        byte[] bys2 = "abc".getBytes();
        fos.write(bys2);

        //   void write(byte[] b, int off, int len):将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流
        fos.write(bys, 0, bys.length);
        fos.write(bys, 1, 1);

        // fos.flush(); //	刷新流,之后还可以继续写数据
        // 3、关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
        fos.close();
    }
}

字符输出流写文件

  • 介绍
    Writer: 用于写入字符流的抽象父类
    FileWriter: 用于写入字符流的常用子类
  • 构造方法
方法名 说明
FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象
FileWriter(File file, boolean append) 根据给定的 File 对象构造一个 FileWriter 对象
FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象
FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象
  • 成员方法
方法名 说明
void write(int c) 写一个字符
void write(char[] cbuf) 写入一个字符数组
void write(char[] cbuf, int off, int len) 写入字符数组的一部分
void write(String str) 写一个字符串
void write(String str, int off, int len) 写一个字符串的一部分
  • 刷新和关闭的方法
方法名 说明
flush() 刷新流,之后还可以继续写数据
close() 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
  • 代码演示
import java.io.FileWriter;
import java.io.IOException;

public class OutputStreamWriterDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileWriter fw = new FileWriter("myCharStream\\a.txt");
        //void write(int c):写一个字符
        fw.write(97);
        fw.write(98);
        fw.write(99);
        // void writ(char[] cbuf):写入一个字符数组        
        char[] chs = {
    
    'a', 'b', 'c', 'd', 'e'};
        fw.write(chs);
        // void write(char[] cbuf, int off, int len):写入字符数组的一部分
        fw.write(chs, 0, chs.length);
        fw.write(chs, 1, 3);
        // void write(String str):写一个字符串
        fw.write("abcde");
        // void write(String str, int off, int len):写一个字符串的一部分
        fw.write("abcde", 0, "abcde".length());
        fw.write("abcde", 1, 3);
        // 释放资源
        fw.close();
    }
}

异常处理-处理释放资源

try-catch-finally

  • 异常处理格式
    • try-catch-finally
try{
    
    	可能出现异常的代码;}catch(异常类名 变量名){
    
    	异常的处理代码;}finally{
    
    	执行所有清除操作;}
  • 示例代码
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo04 {
    
    
    public static void main(String[] args) {
    
    
        //加入finally来实现释放资源      
        FileOutputStream fos = null;
        try {
    
    
            fos = new FileOutputStream("myByteStream\\fos.txt");
            fos.write("hello".getBytes());
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                //最后先关闭输出,在关闭输入,防止空指针异常加入if
                if (fos != null) fos.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

try-catch-resource

jdk1.7后增加了try-with-resources,他是一个声明一个或多个资源的try语句,且()中只能放置资源对象,否则报错。一个资源作为一个对象,必须在程序结束之后关闭。try-with-resources语句确保在语句的最后每个资源都被关闭,任何实现了java.lang.AutoCloseable和java.io.Closeable的对象都可以使用try-with-resource来实现异常处理和关闭资源。

  • 异常处理格式
    • try-catch-resource
try(定义流对象){
    
    

}catch(){
    
    

}
  • 示例代码
public class Test9 {
    
    
//JDK7改进方案
    public static void main(String[] args) {
    
    
        try (//这里只能放置资源对象,用完会自动关闭,自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
             InputStream io = new FileInputStream("src/aaa.txt");
             OutputStream ot = new FileOutputStream("D:/www.txt");
             //int a=1;//报错这里只能写资源
        ) {
    
    

            byte[] arr = new byte[1024];
            int len;
            while ((len = io.read(arr)) != -1) {
    
    
                ot.write(arr, 0, len);
            }
            System.out.println("文件拷贝成功");
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

输出流写数据-换行/追加数据

  • 写数据如何实现换行

    • windows:\r\n
    • linux:\n
    • mac:\r
  • 写数据如何实现追加写入

    • public FileOutputStream(String name,boolean append)
    • 创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头
  • 示例代码

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo03 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建字节输出流对象
        //        FileOutputStream fos = new FileOutputStream("fos.txt");
        FileOutputStream fos = new FileOutputStream("fos.txt", true);
        // 写数据
        for (int i = 0; i < 10; i++) {
    
    
            fos.write("hello".getBytes());
            fos.write("\r\n".getBytes());
        }
        // 释放资源
        fos.close();
    }
}

如何使用字节输入流读取中文内容输出不乱码?

  • 定义一个与文件一样大的字节数组,一次性读取文件全部字节,但是如果文件过大,字节数据可能溢出

字节流复制练习

字节文件输入/输出流

代码

package ioreview.bytestream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author 韦存滨
 * @className Test1
 * @description 文件字节输入/输出流 完成文件复制
 * @date 2023年02月11日 23:17
 */
public class Test1 {
    
    
    public static void main(String[] args) {
    
    
        // 复制 - 其实下载也相当于一个复制,从网下下载到本地

        // 1、创建输出流/输出流
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
    
    
            fileInputStream = new FileInputStream("aa.txt");
            fileOutputStream = new FileOutputStream("bb.txt");

            // 2、读/写数据
            String data = "";
            byte[] bytes = new byte[1024];
            int length;
            while ((length = fileInputStream.read(bytes)) != -1) {
    
    
                // 输出文件到
                fileOutputStream.write(bytes, 0, length);
                data += new String(bytes);
            }

            System.out.println("输出的文件内容为:" + data);

        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            // 3、关闭流
            try {
    
    
                if (fileInputStream != null) {
    
    
                    fileInputStream.close();
                }
                if (fileOutputStream != null) {
    
    
                    fileOutputStream.close();
                }
            } catch (Exception e) {
    
    
            }
        }
    }

}

字节数组输入/输出流

代码

package ioreview.bytestream;

import java.io.*;

/**
 * @author 韦存滨
 * @className Test1
 * @description 字节数组输入/输出流 完成文件复制
 * @date 2023年02月11日 23:17
 */
public class Test2 {
    
    
    public static void main(String[] args) {
    
    
        // 1、创建输出流/输出流
        ByteArrayInputStream byteArrayInputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
    
    
            String data = "abc123测试";
            byte[] dataBytes = data.getBytes();
            byteArrayInputStream = new ByteArrayInputStream(dataBytes);
            byteArrayOutputStream = new ByteArrayOutputStream();

            // 2、读/写数据
            byte[] bytes = new byte[3];
            int length;
            while ((length = byteArrayInputStream.read(bytes)) != -1) {
    
    
                byteArrayOutputStream.write(bytes, 0, length);
                System.out.println(byteArrayOutputStream);
            }
            // 2.1、获取文件内容
            byte[] bytes1 = byteArrayOutputStream.toByteArray();
            String s = new String(bytes1);
            System.out.println("读取的内容是:" + s);
            // 或者直接输出
            System.out.println("读取的内容是:" + byteArrayInputStream.toString());


            int size = byteArrayOutputStream.size();
            // 将此 byte 数组输出流的
            //    count 字段重置为零,从而丢弃输出流中目前已累积的所有输出。通过重新使用已分配的缓冲区空间,
            //    可以再次使用该输出流
            //byteArrayOutputStream.reset();

            // 2.2、将此数组输出流的全部内容写入到指定的输出流参数中
            FileOutputStream fileOutputStream = new FileOutputStream("cc88.txt");
            byteArrayOutputStream.writeTo(fileOutputStream);

        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                if (byteArrayInputStream != null) {
    
    
                    byteArrayInputStream.close();
                }
                if (byteArrayOutputStream != null) {
    
    
                    byteArrayOutputStream.close();
                }
            } catch (Exception e) {
    
    

            }
        }

    }
}

字节缓冲输入/输出流

代码

package ioreview.bytestream;

import java.io.*;

/**
 * @author 韦存滨
 * @className Test1
 * @description 字节缓冲输入/输出流 完成文件复制
 * @date 2023年02月11日 23:17
 */
public class Test3 {
    
    
    public static void main(String[] args) {
    
    
        // 1、创建输出流/输出流
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
    
    
            bufferedInputStream = new BufferedInputStream(new FileInputStream("aa.txt"));
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("bb.txt"));

            String data = "";
            byte[] bytes = new byte[1024];
            int length;
            while ((length = bufferedInputStream.read(bytes)) != -1) {
    
    
                data += new String(bytes);
                bufferedOutputStream.write(bytes, 0, length);
            }
            System.out.println("读取的内容是:" + data);

        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            // 3、关闭流
            try {
    
    
                if (bufferedInputStream != null) {
    
    
                    bufferedInputStream.close();
                }
                if (bufferedOutputStream != null) {
    
    
                    bufferedOutputStream.close();
                }
            } catch (Exception e) {
    
    

            }
        }
    }
}

字节缓冲流——old

缓冲流的主要作用就是提高流的读取,写入效率。

  • 操作方式:字节流字节操作文件,字节缓冲流先将数据添加到缓冲区,再将数据写入到文件中(或者读取文件);
  • 效率:字节缓冲流的效率要高于字节流;(例子:把一堆砖头从A地搬往B地,一块一块的搬(字节流)的效率要远低于 先把砖头装进小推车再运往B地(缓冲流))

字节缓冲流构造方法

  • 构造方法:
方法名 说明
BufferedOutputStream(OutputStream out) 该类实现缓冲输出流.通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
BufferedInputStream(InputStream in) 创建BufferedInputStream将创建一个内部缓冲区数组.当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
  • 示例代码
public class CopyAviDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    

        //复制视频
//        method1();
      	 method2();

    }

    //字节缓冲流一次读写一个字节数组
    public static void method2() throws IOException {
    
    
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\iotest\\字节流复制图片.avi"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));

        byte[] bys = new byte[1024];
        int len;
        while ((len=bis.read(bys))!=-1) {
    
    
            bos.write(bys,0,len);
        }

        bos.close();
        bis.close();
    }

    //字节缓冲流一次读写一个字节
    public static void method1() throws IOException {
    
    
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\iotest\\字节流复制图片.avi"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));

        int by;
        while ((by=bis.read())!=-1) {
    
    
            bos.write(by);
        }

        bos.close();
        bis.close();
    }

}

案例-字节缓冲流复制视频

  • 案例需求
    把“E:\itcast\字节流复制图片.avi”复制到模块目录下的“字节流复制图片.avi”

  • 实现步骤

    • 根据数据源创建字节输入流对象
    • 根据目的地创建字节输出流对象
    • 读写数据,复制视频
    • 释放资源
  • 代码实现

import java.io.*;

public class FileCopy {
    
    
    public static void main(String[] args) {
    
    
        /**
         * 复制文件
         */
        BufferedInputStream in = null;
        BufferedOutputStream out = null;
        try {
    
    
            //abc.txt ->内存
            in = new BufferedInputStream(new FileInputStream("aa.jpg"));
            //内存 ->xyz.txt
            out = new BufferedOutputStream(new FileOutputStream("cc.jpg"));

            //开辟缓冲区 数组 将文件内容在数组中读取
            byte[] buf = new byte[1024];
            int len;
            // int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
            //在不等于-1 说明文件里还有字节 一直输入直到 返回值为-1
            while ((len = in.read(buf)) != -1) {
    
    
                // void write(byte[]b,int off,int len)将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一次写一个字节数组的部分数据
                out.write(buf, 0, len);
            }
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                //最后先关闭输出,在关闭输入,防止空指针异常加入if
                if (out != null) out.close();
                if (in != null) in.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }

        }

    }

}

字符流

为什么会出现字符流

  • 字符流的介绍
    • 由于字节流操作中文不是特别的方便,所以Java就提供字符流
    • 字符流 = 字节流 + 编码表

字符串中的编码解码问题

  • 相关方法
方法名 说明
byte[] getBytes() 使用平台的默认字符集将该 String编码为一系列字节
byte[] getBytes(String charsetName) 使用指定的字符集将该 String编码为一系列字节
String(byte[] bytes) 使用平台的默认字符集解码指定的字节数组来创建字符串
String(byte[] bytes, String charsetName) 通过指定的字符集解码指定的字节数组来创建字符串
  • 代码演示
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class StringDemo {
    
    
    public static void main(String[] args) throws UnsupportedEncodingException {
    
    
        //定义一个字符串
        String s = "123中";
        byte[] bys1 = s.getBytes();  // 当前默认编码方式
        byte[] bys2 = s.getBytes("UTF-8");
        byte[] bys3 = s.getBytes("GBK");
        System.out.println(Arrays.toString(bys1)); // [49, 50, 51, -28, -72, -83]
        System.out.println(Arrays.toString(bys2)); // [49, 50, 51, -28, -72, -83]
        System.out.println(Arrays.toString(bys3)); // [49, 50, 51, -42, -48]

        String ss1 = new String(bys1); // 123中
        String ss2 = new String(bys1, "UTF-8"); // 123中
        String ss3 = new String(bys1, "GBK"); // 123涓�
        System.out.println(ss1);
        System.out.println(ss2);
        System.out.println(ss3);
    }
}

字符缓冲流

  • 字符缓冲流介绍

    • BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
    • BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途
  • 构造方法

方法名 说明
BufferedWriter(Writer out) 创建字符缓冲输出流对象
BufferedReader(Reader in) 创建字符缓冲输入流对象
  • 代码演示
import java.io.*;

public class BufferedStreamDemo01 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //BufferedWriter(Writer out)
        BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
        bw.write("hello\r\n");
        bw.write("world\r\n");
        bw.close();

        // BufferedReader(Reader in)
        BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));
        // 一次读取一个字符数据
        int ch;
        while ((ch = br.read()) != -1) {
    
    
            System.out.print((char) ch);
        }
        // 一次读取一个字符数组数据
        char[] chs = new char[1024];
        int len;
        while ((len = br.read(chs)) != -1) {
    
    
            System.out.print(new String(chs, 0, len));
        }
        br.close();
    }
}

字符缓冲流特有功能

  • 方法介绍
    BufferedWriter:
    BufferedReader:
方法名 说明
void newLine() 写一行行分隔符,行分隔符字符串由系统属性定义
方法名 说明
String readLine() 读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null
  • 代码演示
import java.io.*;

public class BufferedStreamDemo02 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建字符缓冲输出流
        BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
        // 写数据
        for (int i = 0; i < 10; i++) {
    
    
            bw.write("hello" + i);
            bw.write("\r\n");
            bw.newLine();
            bw.flush();
        }
        // 释放资源
        bw.close();
        
        // 创建字符缓冲输入流
        BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));
        String line;
        while ((line = br.readLine()) != null) {
    
    
            System.out.println(line);
        }
        br.close();
    }
}

转换流

字符流中和编码解码问题相关的两个类

  • InputStreamReader:是从字节流到字符流的桥梁,父类是Reader
    它读取字节,并使用指定的编码将其解码为字符
    它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
  • OutputStreamWriter:是从字符流到字节流的桥梁,父类是Writer
    是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节
    它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集

转换流读写数据

  • 构造方法
方法名 说明
InputStreamReader(InputStream in) 使用默认字符编码创建InputStreamReader对象
InputStreamReader(InputStream in,String chatset) 使用指定的字符编码创建InputStreamReader对象
OutputStreamWriter(OutputStream out) 使用默认字符编码创建OutputStreamWriter对象
OutputStreamWriter(OutputStream out,String charset) 使用指定的字符编码创建OutputStreamWriter对象
  • 代码演示
import java.io.*;

public class ConversionStreamDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("fos.txt"));
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("fos.txt"), "GBK");
        osw.write("中国");
        osw.close();

        InputStreamReader isr = new InputStreamReader(new FileInputStream("fos.txt"));
        //InputStreamReader isr = new InputStreamReader(new FileInputStream("fos.txt"), "GBK");
        // 一次读取一个字符数据
        int ch;
        while ((ch = isr.read()) != -1) {
    
    
            System.out.print((char) ch);
        }
        isr.close();
    }
}

对象操作流

对象序列化流

序列化:将对象的状态信息转换为可以存储或传输的形式的过程。程序通过序列化把Java对象转换成二进制字节流,然后就可以把二进制字节流写入网络或磁盘。

反序列化:读取磁盘或网络中的二进制字节流数据,转化为Java对象

序列化流:ObjectOutputStream

反序列化流:ObjectInputStream

注意事项

    • 一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口
    • Serializable是一个标记接口,实现该接口,不需要重写任何方法
  • 对象序列化介绍

    • 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
    • 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
    • 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
    • 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
  • 对象序列化流: ObjectOutputStream

    • 将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象
  • 构造方法

方法名 说明
ObjectOutputStream(OutputStream out) 创建一个写入指定的OutputStream的ObjectOutputStream
  • 序列化对象的方法
方法名 说明
void writeObject(Object obj) 将指定的对象写入ObjectOutputStream
  • 示例代码
    学生类
    测试类
public class Student implements Serializable {
    
    
    private String name;
    private int age;

    public Student() {
    
    
    }

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

    public String getName() {
    
    
        return name;
    }

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

    public int getAge() {
    
    
        return age;
    }

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

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

 

public class ObjectOutputStreamDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
        // 创建对象
        Student s = new Student("佟丽娅", 30);
        // void writeObject(Object obj):将指定的对象写入ObjectOutputStream
        oos.writeObject(s);
        // 释放资源
        oos.close();
    }
}

对象反序列化流

  • 对象反序列化流: ObjectInputStream

    • ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
  • 构造方法

方法名 说明
ObjectInputStream(InputStream in) 创建从指定的InputStream读取的ObjectInputStream
  • 反序列化对象的方法
方法名 说明
Object readObject() 从ObjectInputStream读取一个对象
  • 示例代码
public class ObjectInputStreamDemo {
    
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
        //ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));

        //Object readObject():从ObjectInputStream读取一个对象
        Object obj = ois.readObject();

        Student s = (Student) obj;
        System.out.println(s.getName() + "," + s.getAge());

        ois.close();
    }
}

serialVersionUID&transient

  • serialVersionUID

    • 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?

      • 会出问题,会抛出InvalidClassException异常
    • 如果出问题了,如何解决呢?

      • 重新序列化
    • 给对象所属的类加一个serialVersionUID

      • private static final long serialVersionUID = 42L;
  • transient

    • 如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
      • 给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
  • 示例代码
    学生类
    测试类

public class Student implements Serializable {
    
    
    //private static final long serialVersionUID = 42L;
    private String name;
    //private int age;
    private transient int age;

    public Student() {
    
    
    }

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

    public String getName() {
    
    
        return name;
    }

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

    public int getAge() {
    
    
        return age;
    }

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

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



public class ObjectStreamDemo {
    
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
        write();
        read();
    }

    //序列化
    private static void write() throws IOException {
    
    
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));
        Student s = new Student("佟丽娅", 20);
        oos.writeObject(s);
        oos.close();
    }
    //反序列化
    private static void read() throws IOException, ClassNotFoundException {
    
    
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));
        Object obj = ois.readObject();
        Student s = (Student) obj;
        System.out.println(s.getName() + "," + s.getAge());
        ois.close();
    }

}

对象操作流练习

  • 案例需求
    创建多个学生类对象写到文件中,再次读取到内存中

  • 实现步骤

    • 创建序列化流对象
    • 创建多个学生对象
    • 将学生对象添加到集合中
    • 将集合对象序列化到文件中
    • 创建反序列化流对象
    • 将文件中的对象数据,读取到内存中
  • 代码实现
    学生类
    测试类

public class Student implements Serializable{
    
    
    
    private static final long serialVersionUID = 2L;

    private String name;
    private int age;

    public Student() {
    
    
    }

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

    public String getName() {
    
    
        return name;
    }

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

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }
}
public class Demo03 {
    
    
    /**
     *  read():
     *      读取到文件末尾返回值是 -1
     *  readLine():
     *      读取到文件的末尾返回值 null
     *  readObject():
     *      读取到文件的末尾 直接抛出异常
     *  如果要序列化的对象有多个,不建议直接将多个对象序列化到文件中,因为反序列化时容易出异常
     *      建议: 将要序列化的多个对象存储到集合中,然后将集合序列化到文件中
     */
    public static void main(String[] args) throws Exception {
    
    
        /*// 序列化
        //1.创建序列化流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myCode\\oos.txt"));
        ArrayList<Student> arrayList = new ArrayList<>();
        //2.创建多个学生对象
        Student s = new Student("佟丽娅",30);
        Student s01 = new Student("佟丽娅",30);
        //3.将学生对象添加到集合中
        arrayList.add(s);
        arrayList.add(s01);
        //4.将集合对象序列化到文件中
        oos.writeObject(arrayList);
        oos.close();*/

        // 反序列化
      	//5.创建反序列化流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myCode\\oos.txt"));
      	//6.将文件中的对象数据,读取到内存中
        Object obj = ois.readObject();
        ArrayList<Student> arrayList = (ArrayList<Student>)obj;
        ois.close();
        for (Student s : arrayList) {
    
    
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

打印流

Properties集合

Properties作为Map集合的使用

  • Properties介绍

    • 不属于io流体系,
    • 是一个Map体系的集合类
    • Properties可以保存到流中或从流中加载
    • 属性列表中的每个键及其对应的值都是一个字符串
  • Properties基本使用

package cc;

import java.util.Properties;
import java.util.Set;

public class PropertiesDemo01 {
    
    
    public static void main(String[] args) {
    
    
        //创建集合对象
//        Properties<String,String> prop = new Properties<String,String>(); //错误
        Properties prop = new Properties();

        //存储元素
        prop.put("itheima001", "佟丽娅");
        prop.put("itheima002", "赵丽颖");
        prop.put("itheima003", "刘诗诗");
 
        //遍历集合
        Set<Object> keySet = prop.keySet();
        for (Object key : keySet) {
    
    
            Object value = prop.get(key);
            System.out.println(key + "," + value);
        }
    }
}

Properties作为Map集合的特有方法

  • 特有方法
方法名 说明
Object setProperty(String key, String value) 设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
String getProperty(String key) 使用此属性列表中指定的键搜索属性
Set stringPropertyNames() 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
  • 示例代码
package cc;

import java.util.Properties;
import java.util.Set;

public class PropertiesDemo02 {
    
    
    public static void main(String[] args) {
    
    
        //创建集合对象
        Properties prop = new Properties();

        //Object setProperty(String key, String value):设置集合的键和值,都是String类型
        prop.setProperty("itheima001", "佟丽娅");
        prop.setProperty("itheima002", "赵丽颖");
        prop.setProperty("itheima003", "刘诗诗");

        //String getProperty(String key):使用此属性列表中指定的键搜索属性
//        System.out.println(prop.getProperty("itheima001"));
//        System.out.println(prop.getProperty("itheima0011"));

//        System.out.println(prop);

        //Set<String> stringPropertyNames():从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
        Set<String> names = prop.stringPropertyNames();
        for (String key : names) {
    
    
//            System.out.println(key);
            String value = prop.getProperty(key);
            System.out.println(key + "," + value);
        }
    }
}

Properties和IO流相结合的方法

  • 和IO流结合的方法
方法名 说明
void load(Reader reader) 从输入字符流读取属性列表(键和元素对)
void store(Writer writer, String comments) 将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流
  • 示例代码
package cc;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class PropertiesDemo03 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //把集合中的数据保存到文件
        myStore();

        //把文件中的数据加载到集合
        myLoad();

    }

    private static void myLoad() throws IOException {
    
    
        Properties prop = new Properties();

        //void load(Reader reader):
        FileReader fr = new FileReader("fw.txt");
        prop.load(fr);
        fr.close();

        System.out.println(prop);
    }

    private static void myStore() throws IOException {
    
    
        Properties prop = new Properties();

        prop.setProperty("itheima001", "佟丽娅");
        prop.setProperty("itheima002", "赵丽颖");
        prop.setProperty("itheima003", "刘诗诗");

        //void store(Writer writer, String comments):
        FileWriter fw = new FileWriter("fw.txt");
        prop.store(fw, null);
        fw.close();
    }
}

Properties集合练习

  • 案例需求
    在Properties文件中手动写上姓名和年龄,读取到集合中,将该数据封装成学生对象,写到本地文件

  • 实现步骤

    • 创建Properties集合,将本地文件中的数据加载到集合中
    • 获取集合中的键值对数据,封装到学生对象中
    • 创建序列化流对象,将学生对象序列化到本地文件中
  • 代码实现
    学生类
    测试类

public class Student implements Serializable {
    
    
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;

    public Student() {
    
    
    }

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

    public String getName() {
    
    
        return name;
    }

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

    public int getAge() {
    
    
        return age;
    }

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

    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test {
    
    

    public static void main(String[] args) throws IOException {
    
    
      	//1.创建Properties集合,将本地文件中的数据加载到集合中
        Properties prop = new Properties();
        FileReader fr = new FileReader("prop.properties");
        prop.load(fr);
        fr.close();
		//2.获取集合中的键值对数据,封装到学生对象中
        String name = prop.getProperty("name");
        int age = Integer.parseInt(prop.getProperty("age"));
        Student s = new Student(name,age);
		//3.创建序列化流对象,将学生对象序列化到本地文件中
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
        oos.writeObject(s);
        oos.close();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44797182/article/details/130290812