java学习笔记---5

IO流

I〇流概述:

  • lO:输入/输出(Input/Output)
  • 流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输IO流就是用来处理设备间数据传输问题的;
  • 常见的应用:文件复制;文件上传;文件下载

IO流分类:

  • 按照数据的流向

输入流:读数据
输出流:写数据

  • 按照数据类型来分

字节流:字节输入流;字节输出流
字符流:字符输入流;字符输出流

一般来说,我们说lO流的分类是按照数据类型来分的那么这两种流都在什么情况下使用呢?
如果数据通过Window自带的记事本软件打开,我们还可以读懂里面的内容,就使用字符流,否则使用字节流。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

53.File类

1.File类概述

File:它是文件和目录路径名的抽象表示

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

2.构造方法

方法名说明
File(String pathname)通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
File(String parent, String child)从父路径名字符串和子路径名字符串创建新的File实例
File(File parent, String child)从父抽象路径名和子路径名字符串创建新的File实例
import java.io.File;

public class FileDemo1 {
    public static void main(String[] args) {

//        File(String pathname)|通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
        File f1 = new File("E:\\Java Demos\\files\\java.txt");
        System.out.println(f1);
        
//        File(String parent, String child)|从父路径名字符串和子路径名字符串创建新的File实例
        File f2 = new File("E:\\Java Demos\\files","java.txt");
        System.out.println(f2);
        
//        File(File parent, String child)|从父抽象路径名和子路径名字符串创建新的File实例
        File f3 = new File("E:\\Java Demos\\files");
        File f4 = new File(f3,"java.txt");
        System.out.println(f4);
        
    }
}

3.File类创建功能

方法名说明
public boolean createNewFile()当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir()创建由此抽象路径名命名的目录
public boolean mkdirs()创建多级目录

//如果文件或者目录存在就返回false,不存在 创建并返回true
//创建文件之前首先一个先创建文件目录

package Files;

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

//        public boolean createNewFile()|当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
//        public boolean mkdir()|创建由此抽象路径名命名的目录
//        public boolean mkdirs()|创建多级目录
public class FileDemo2 {
    public static void main(String[] args) throws IOException {
        //需求1: 在E:\Java Demos\itcast 下创建一个文件 java.txt
        File f1 = new File("E:\\Java Demos\\itcast\\java.txt");
        System.out.println(f1.createNewFile());

        //需求2: 在E:\Java Demos\itcast创建一个目录JavaSe
        File f2 = new File("E:\\Java Demos\\itcast\\JavaSe");
        System.out.println(f2.mkdir());

        //需求3:在 在E:\Java Demos\itcast 下创建创建多级目录JavaWeb\Html
        File f3 = new File("E:\\Java Demos\\itcast\\JavaWeb\\Html");
        System.out.println(f3.mkdirs());
    }
}

在这里插入图片描述
4.File类判断和获取功能

方法名说明
public boolean isDirectory()测试此抽象路径名表示的File是否为目录
public boolean isFile()测试此抽象路径名表示的File是否为文件
public boolean exists()测试此抽象路径名表示的File是否存在
public String getAbsolutePath()返回此抽象路径名的绝对路径名字符串
public String getPath()将此抽象路径名转换为路径名字符串
public String getName()返回由此抽象路径名表示的文件或目录的名称
public String[] list()返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles()返回此抽象路径名表示的目录中的文件和目录的File对象数组
//        public String[] list()|返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
//        public File[] listFiles()|返回此抽象路径名表示的目录中的文件和目录的File对象数组
        File f4 = new File("E:\\Java Demos\\itcast");
        String[] strArray = f4.list();
        for(String str:strArray){
            System.out.println(str);
        }
        //java.txt
        // JavaSe
        //JavaWeb

        File[] fileArray = f4.listFiles();
        for(File f:fileArray){
            System.out.println(f+"文件名:"+f.getName());
        }
//        E:\Java Demos\itcast\java.txt文件名:java.txt
//        E:\Java Demos\itcast\JavaSe文件名:JavaSe
//        E:\Java Demos\itcast\JavaWeb文件名:JavaWeb

5. File类删除功能

方法名说明
public boolean delete()删除由此抽象路径名表示的文件或目录

绝对路径和相对路径的区别

  • 绝对路径: 完整的路径名,不需要任何其他信息就可以定位它所表示的文件。例如:E\itcast\java.txt
  • 相对路径: 必须使用取自其他路径名的信息讲行解释。例收:myFile\java.txt

// 删除目录之前 应该先删除目录下的内容;

package Files;

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

public class FileDemo3 {
    public static void main(String[] args) throws IOException {

        //需求1:在当前模块目录下创建java.txt文件
        File f = new File("java.txt");
        System.out.println(f.createNewFile());

        //需求2:删除当前目录文件下创建的java.txt文件
        System.out.println(f.delete());
    }
}

6.递归

概述: 在方法中调用方法本身;

递归解决问题的思路:
把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算

递归解决问题要找到两个内容:

  • 递归出口:否则会出现内存溢出 递归规则:
  • 与原问题相似的规模较小的问题

应用情景举例:

public class NoDieRabbit {
    public static void main(String[] args) {
        //有一对兔子,从出生的第三个月起每个月都生一对兔子,小兔子张到第三个月也是每个月又生一对
        //假如兔子都不死,问这20个月兔子的对数为多少?
        int[] arr = new int[20];
        arr[0] = 1;
        arr[1] = 2;
        System.out.println("第"+1+"个月的兔子个数为"+arr[0]);
        System.out.println("第"+2+"个月的兔子个数为"+arr[1]);
        for (int i = 2; i < arr.length; i++) {
            arr[i] = arr[i - 2] + arr[i - 1];
            System.out.println("第"+(i+1)+"个月的兔子个数为"+arr[i]);
        }

    }
}
/*规律:
*       第一个月:1
*       第二个月:1
*       第三个月:2    =====>斐波那契数列
*       第四个月:3
*       第五个月:5
* */

递归解决方法:

package Files;

public class NoDieRabbit {
    public static void main(String[] args) {
        System.out.println(month(20));
    }
    public static int month(int n){
        if(n==1||n==2){
            return 1;
        }else {
            return month(n-1)+month(n-2);
        }
    }
}

7.案例 :递归求阶乘

package Files;

public class JieCheng {
    public static void main(String[] args) {
        System.out.println(jc(4));
    }
    public static int jc(int n){
        if(n==1){
            return 1;
        }else {
            return n*jc(n-1);
        }
    }
}

8.遍历目录

需求:
给定一个路径(E\itcast),请通过递归完成遍历该目录下的所有内容,并把所有文件的绝对路径输出在控制台

思路:

  1. 根据给定的路径创建一个File对象
  2. 定义一个方法,用于获取给定目录下的所有内容,参数为第1步创建的File对象
  3. 获取给定的File目录下所有的文件或者目录的File数组
  4. 遍历该File数组,得到每一个File对象
  5. 判断该File对象是否是目录
    是:递归调用 不是:获取绝对路径输出在控制台
  6. 调用方法
package Files;

import java.io.File;

public class BianLiDir {
    public static void main(String[] args) {

        //给定路径下创建一个File对象
        File f = new File("E:\\Java Demos\\itcast");
        bl(f);
    }
    //定义方法,用于获取给定目录下的所有内容,参数为第一步创建的file对象
    public static void bl(File f) {
        //获取给定的file目录下所有的文件或者目录file数组
        File[] fileArray = f.listFiles();
        //遍历该file数组,得到每一个file对象
        if(fileArray != null){
            for(File file:fileArray){
                if(file.isDirectory()) {
                    bl(file);
                }else {
                    System.out.println(file.getAbsolutePath());
                }
            }
        }
        System.out.println(f.getAbsolutePath());
    }
}

在这里插入图片描述

54.字节流

1.字节流写数据

字节流抽象基类

  • lnputStream:这个抽象类是表示字节输入流的所有类的超类
  • OutputStream:这个抽象类是表示字节输出流的所有类的超类
  • 子类名特点:子类名称都是以其父类名作为了类名的后缀

FileOutputStream:文件输出流用于将数据写入File

  • FileOutputStream(Stringname):创建文件输出流以指定的名称写入文件

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

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

//FileOutputStream(Stringname):创建文件输出流以指定的名称写入文件

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

public class FileStreamDemo {
    public static void main(String[] args) throws IOException {

        FileOutputStream fos = new FileOutputStream("fos.txt");

        //直接写入数字的是对应ascall的字符
        fos.write(15);

        //所有和io相关的数据 最终都要释放资源
        fos.close();
    }
}

在这里插入图片描述

2.字节流写数据的三种方式

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

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class FileScreamDemo1 {
    public static void main(String[] args) throws IOException {

        FileOutputStream flo = new FileOutputStream("fos.txt");

        flo.write(12);  //一次写一个字节

        byte[] by = {97,98,99,100,101,102};  //写一个字节数组
        flo.write(by);
        byte[] bytes = "ghjk".getBytes(StandardCharsets.UTF_8);  //快捷方式搞到字节数组
        flo.write(bytes);

        flo.write(bytes,1,bytes.length-1);  //hjk
        flo.close();

    }
}

在这里插入图片描述

3 字节流写数据的两个小问题

  • 字节流写数据如何实现换行呢?

写完数据后,加换行符
windows:\rinlinux:\n
mac:\r

  • 字节流写数据如何实现追加写入呢?

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

package Files;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class FileStreamDemo4 {
    public static void main(String[] args) throws IOException {

        FileOutputStream fos = new FileOutputStream("fos.txt");

        fos.write("hello".getBytes(StandardCharsets.UTF_8));
        fos.write("\n".getBytes(StandardCharsets.UTF_8));   //换行
        fos.write("nihao".getBytes(StandardCharsets.UTF_8));
        
//        fos.close();
    }
}

package Files;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class FileStreamDemo3 {
    public static void main(String[] args) throws IOException {

        //追加写入
        FileOutputStream fos = new FileOutputStream("fos.txt");

        fos.write("byebye".getBytes(StandardCharsets.UTF_8));
        fos.close();



    }
}

4.字节流异常处理

finally:
在异常处理时提供finally块来执行所有清除操作。比如说IO流中的释放资源特点:被finally控制的语句一定会执行,除非JVM退出

try{
可能出现异常的代码;}
catch(异常类名变量名){
异常的处理代码;}
finally{
执行所有清除操作;
}
package Files;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class FileStreamDemo3 {
    public static void main(String[] args) throws IOException {

        //追加写入
        FileOutputStream fos = new FileOutputStream("fos.txt");

        fos.write("byebye".getBytes(StandardCharsets.UTF_8));
        fos.close();



    }
}

5.字节流读数据(一次读一个字节数据)

需求:
把文件fos.txt中的内容读取出来在控制台输出

FilelnputStream:从文件系统中的文件获取输入字节 FilelnputStream(String
name):通过打开与实际文件的连接来创建一个FilelnputStream,该文件由文件系统中的路径名name命名

使用字节输入流读数据的步骤:

创建字节输入流对象
调用字节输入流对象的读数据方法
释放资源

package Files;

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

public class FileStreamDemo2 {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("fos.txt");

        //读取第一个数据
        int read = fis.read();
        System.out.println(read);   //104
        System.out.println((char) read);  //h

        //如果读到文件末尾返回-1
        while (read!=-1){
            System.out.println(read);
            System.out.println((char) read);
            read = fis.read();
        }
        fis.close();


    }
}

FileInputStream fis = new FileInputStream("fos.txt");

        //优化读取
        int read = fis.read();
        while ((read=fis.read())!=-1){
            System.out.print((char) read);
        }
        
        fis.close();

6 字节流读取数据(一次读一个字节数组数据)

需求: 把文件fos.txt中的内容读取出来在控制台输出

使用字节输入流读数据的步骤:

  1. 创建字节输入流对象
  2. 调用字节输入流对象的读数据方法
  3. 释放资源
package Files;

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

public class FileStreamDemo2 {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("fos.txt");

        byte[] b = new byte[5];
        int len = fis.read(b);
        System.out.println(len);   //表示读取的个数
        System.out.println(new String(b));

//        5
//        hello

        len = fis.read(b);
        System.out.println(len);
        System.out.println(new String(b,0,len));
        fis.close();

//        5
//
//        niha
    }
}

优化改进:

package Files;

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

public class FileStreamDemo2 {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("fos.txt");

        byte[] bys = new byte[1024];  //这里一般采用1024或者其整数被
        int len;
        while ((len=fis.read(bys))!=-1){
            System.out.println(new String(bys,0,len));
        }

        fis.close();

//        hello nihao
    }
}

7 字节流复制文本、图片、视频文件、文件夹

7.1 复制文本

需求: 把“E:\itcast\Java之诗.txt”复制到模块目录下的“Java之诗.txt"

分析:

  1. 复制文本文件,其实就把文本文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(目的地)
  2. 数据源:E:\litcast\窗里窗外.txt—读数据— InputStream —FilelnputStream
  3. 目的地:myByteStream\l窗里窗外.txt —写数据—OutputStream — FileOutputStream
package Files;

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

public class CopyTxt {
    public static void main(String[] args) throws IOException {

        //根据数据源创建字节输入流对象
        FileInputStream fis = new FileInputStream("E:\\Java Demos\\itcast\\Java之诗.txt");

        //根据目的地创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("java之诗.txt");

        //读取数据
        int by;
        while ((by=fis.read())!=-1){
            fos.write(by);
        }

        //释放资源
        fis.close();
        fos.close();

    }
}

在这里插入图片描述

7.2 复制图片

需求: 把“E:\litcast\mn.jpg”复制到模块目录下的“mn.jpg"

思路:

  1. 根据数据源创建字节输入流对象
  2. 根据目的地创建字节输出流对象
  3. 读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
  4. 释放资源
package Files;

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

public class JpgCopy {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("E:\\Java Demos\\itcast\\mn.jpg");
        FileOutputStream fos = new FileOutputStream("mn.jpg");

        byte[] b = new byte[1024];
        int len;

        while ((len=fis.read(b))!=-1){
            fos.write(b,0,len);
        }

        fos.close();
        fis.close();

    }
}

我的小土豆:
在这里插入图片描述

7.3 复制视频

需求: 把“E:\itcast\豆豆.av”复制到模块目录下的“豆豆.av"

思路:

  1. 根据数据源创建字节输入流对象
  2. 根据目的地创建字节输出流对象
  3. 读写数据,复制视频
  4. 释放资源
package Files;

//四种方式实现复制视频,并记录每种方式复制视频的时间
//        1:基本字节流一次读写一个字节
//        2 :基本字节流一次读写一个字节数组
//        3:字节缓冲流一次读写一个字节
//        4 :字节缓冲流一次读写一个字节数组

import java.io.*;

public class VideoCopy {
    public static void main(String[] args) throws IOException {

        //记录开始时间
        long startTime = System.currentTimeMillis();

        //复制视频

        //method1();
//        method2();   //耗时:95ms
//        method3();     //耗时:547ms
        method4();
        //记录结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("耗时:"+(endTime-startTime)+"ms");
    }

    private static void method4() throws IOException {
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("E:\\Java Demos\\itcast\\豆豆.MP4"));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("土豆.MP4"));

        byte[] by= new byte[1024];
        int len;
        while ((len=bufferedInputStream.read())!=-1){
            bufferedOutputStream.write(by,0,len);
        }
        bufferedInputStream.close();
        bufferedOutputStream.close();
    }

    // 3:字节缓冲流一次读写一个字节
    private static void method3() throws IOException {
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("E:\\Java Demos\\itcast\\豆豆.MP4"));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("土豆.MP4"));

        int by;
        while ((by=bufferedInputStream.read())!=-1){
            bufferedOutputStream.write(by);
        }
        bufferedInputStream.close();
        bufferedOutputStream.close();
    }

//    2 :基本字节流一次读写一个字节数组
    private static void method2() throws IOException {
        FileInputStream fileInputStream = new FileInputStream("E:\\Java Demos\\itcast\\豆豆.MP4");
        FileOutputStream fileOutputStream = new FileOutputStream("土豆.MP4");

        byte[] by = new byte[1024];
        int len;
        while ((len=fileInputStream.read(by))!=-1){
            fileOutputStream.write(by,0,len);
        }
        fileOutputStream.close();
        fileInputStream.close();
    }

    //1:基本字节流一次读写一个字节
    private static void method1() throws IOException {
        FileInputStream fileInputStream = new FileInputStream("E:\\Java Demos\\itcast\\豆豆.MP4");
        FileOutputStream fileOutputStream = new FileOutputStream("土豆.MP4");

        int by;
        while ((by=fileInputStream.read())!=-1){
            fileOutputStream.write(by);
        }
        fileOutputStream.close();
        fileInputStream.close();
    }


}

7.4复制单极文件夹

需求:
把“E:\litcast”这个文件夹复制到模块目录下

思路:

  1. 创建数据源目录File对象,路径是E:\litcast
  2. 获取数据源目录File对象的名称(itcast)
  3. 创建目的地目录File对象,路径名是模块名+itcast组(myCharStream\itcast)
  4. 判断目的地目录对应的File是否存在,如果不存在,就创建
  5. 获取数据源目录下所有文件的File数组 遍历File数组,得到每一个File对象,该File对象,其实就是数据源文件
  6. 数据源文件:E:\litcast\lmn.jpg
  7. 获取数据源文件File对象的名称(mn.jpg)
  8. 创建目的地文件File对象,路径名是目的地目录+mn.jpg组成(myCharStreaml|itcast\lmn.jpg)
  9. 复制文件
    由于文件不仅仅是文本文件,还有图片,视频等文件,所以采用字节流复制文件

在这里插入图片描述

package Files;

import java.io.*;

public class FolderCopy {
    public static void main(String[] args) throws IOException {
        //复制文件夹

        //创建数据源目录对象
        File srcFolder = new File("E:\\Java Demos\\itcast");

        //获取数据源目录File对象名称
        String srcFolderName = srcFolder.getName();

        //创建目的地File对象
        File destFolder = new File(srcFolderName);

        //判断目的地目录对应的file是否存在,不存在就创建
        if (!destFolder.exists()){
            destFolder.mkdir();
        }

        //获取数据源目录下所有文件的File数组
        File[] listFiles = srcFolder.listFiles();

        //遍历File数组,得到每一个File对象,该File对象其实就是源文件
        for (File srcFile:listFiles){
            String srcFileName = srcFile.getName();
            File destFile = new File(srcFileName);
            //复制文件
            copyFile(srcFile,destFile);
        }


    }

    public static void copyFile(File srcFile, File destFile) throws IOException {

        BufferedInputStream bi = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(destFile));

        byte[] by = new byte[1024];
        int len;
        while ((len=bi.read(by))!=-1){
            bo.write(by,0,len);
        }
        bi.close();
        bo.close();
    }


}

7.5 复制多级文件

需求:
把“E:\litcast”复制到F盘目录下

思路:

  1. 创建数据源File对象,路径是E:\itcast
  2. 创建目的地File对象,路径是F:\
  3. 写方法实现文件夹的复制,参数为数据源File对象和目的地File对象
  4. 判断数据源File是否是目录
    是:
    A:在目的地下创建和数据源File名称一样的目录
    B:获取数据源File下所有文件或者目录的File数组
    C:遍历该File数组,得到每一个File对象
    D:把该File作为数据源File对象,递归调用复制文件夹的方法
    不是:
    说明是文件,直接复制,用字节流
package Files;

import java.io.*;

public class FoldersCopy {
    public static void main(String[] args) throws IOException {
        //复制多级目录

        //创建数据源File对象
        File srcFile = new File("E:\\Java Demos\\itcast");

        //创建目的地File对象
        File destfile = new File("F:\\");

        //写方法实现文件夹复制 参数为源File,和目的File
        copyFolder(srcFile,destfile);
    }

    private static void copyFolder(File srcFile, File destfile) throws IOException {
        //判断是不是目录
        if(srcFile.isDirectory()){
            String srcFileName = srcFile.getName();
            File newFolder = new File(destfile,srcFileName);
            if(!newFolder.mkdir()){
                newFolder.mkdir();
            }
            File[] fileArray = srcFile.listFiles();
            for (File file:fileArray){
                copyFolder(file,newFolder);
            }

        }else {  //不是目录说明是文件直接就复制
            File newFile = new File(destfile, srcFile.getName());
            copyFile(srcFile, newFile);
        }
    }

    public static void copyFile(File srcFile, File destFile) throws IOException {

        BufferedInputStream bi = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(destFile));

        byte[] by = new byte[1024];
        int len;
        while ((len=bi.read(by))!=-1){
            bo.write(by,0,len);
        }
        bi.close();
        bo.close();
    }


}

复制成功
在这里插入图片描述

8.字节缓冲流

字节缓冲流:

  • BufferOutputstream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
  • BufferedInputStream:创建BufferedInputstream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

构造方法:

  • 字节缓冲输出流:BufferedOutputStream(OutputStreamout)
  • 字节缓冲输入流:BufferedInputStream(InputStream in)

为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?

字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作

package Files;

import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class BufferStreamDemo {
    public static void main(String[] args) throws IOException {

        //字符缓冲输出流
//        FileOutputStream fos = new FileOutputStream("bos.txt");
//        BufferedOutputStream bos = new BufferedOutputStream(fos);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));

        //写数据
        bos.write("hello\r\n".getBytes(StandardCharsets.UTF_8));
        bos.write("world".getBytes(StandardCharsets.UTF_8));

        bos.close();
    }
}

package Files;

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

public class BufferStreamDemo1 {
    public static void main(String[] args) throws IOException {

        //字节缓存输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bos.txt"));

        //读数据
//        一次读一个字节
        int by;
        while ((by=bis.read())!=-1){
            System.out.print((char) by);
        }
//        hello
//                world

        //一次读一个字节组
        byte[] bytes = new byte[1024];
        int len;
        while ((len=bis.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }
        
        bis.close();

    }
}

55. 字符流

1.为什么会出现字符流

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

用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?

●汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

一个汉字存储

  • 如果是GBK编码,占用2个字节
  • 如果是UTF-8编码,占用3个字节
package Files;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class FileStreamDemo5 {
    public static void main(String[] args) throws IOException {


        byte[] b = "abc".getBytes();   //[97, 98, 99]
        System.out.println(Arrays.toString(b));

        //采用utf-8一个汉族占三个字节(默认)
        byte[] by = "中国".getBytes(StandardCharsets.UTF_8);
        System.out.println(Arrays.toString(by));  //[-28, -72, -83, -27, -101, -67]

        //采用GBK格式 一个汉族占用两个字节
        byte[] byt = "中国".getBytes("GBK");
        System.out.println(Arrays.toString(byt));  //[-42, -48, -71, -6]

    }
}

2.编码表

相关链接:https://blog.csdn.net/meini32/article/details/125852180

3.字符串中的编码解码问题

  • 编码:
方法名说明
byte[] getBytes():使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
byte[] getBytes(String charsetName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
  • 解码:
方法名说明
String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String;
String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的String
package Files;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class StringDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {

        //编码
        String s = "中国";

        byte[] b = s.getBytes();                    //默认编码
        System.out.println(Arrays.toString(b));    //[-28, -72, -83, -27, -101, -67]

        byte[] b1 = s.getBytes("UTF-8");    //指定编码
        System.out.println(Arrays.toString(b1));    //[-28, -72, -83, -27, -101, -67]

        byte[] b2 = s.getBytes("GBK");
        System.out.println(Arrays.toString(b2));   //[-42, -48, -71, -6]

        //解码
        String ss = new String(b);  //默认解码
        System.out.println(ss);   //中国

        String ss1 = new String(b1,"UTF-8");  //指定解码
        System.out.println(ss1);

        String ss2 = new String(b2,"GBK");
        System.out.println(ss2);
    }
}

4.字符流中的编码解码问题字符流抽象基类

Reader:字符输入流的抽象类
Writer:字符输出流的抽象类

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

  • InputStreamReader:是从字节流到字符流的桥梁

它读取字节,并使用指定的编码将其解码为字符
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集

  • OutputStreamriter:是从字符流到字节流的桥梁

是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集

package Files;

import org.omg.CORBA.portable.OutputStream;

import java.io.*;

public class BufferStreaamDemo2 {
    public static void main(String[] args) throws IOException {
        //字节流到字符流  InputStreamReader
        //反之:OutputStreamWriter

        OutputStreamWriter opsw = new OutputStreamWriter(new FileOutputStream("opsw.txt"));  //默认
        opsw.write("中国");
        opsw.close();

        OutputStreamWriter opsw = new OutputStreamWriter(new FileOutputStream("opsw.txt"),"UTF-8");  //utf-8
        opsw.write("中国");  //中国
        opsw.close();

        OutputStreamWriter opsw = new OutputStreamWriter(new FileOutputStream("opsw.txt"),"GBK");  //GBK
        opsw.write("中国");   //�й�
        opsw.close();

        
        //字符流读数据
        InputStreamReader ipsr = new InputStreamReader(new FileInputStream("opsw.txt"),"GBK");

        int ch;
        while ((ch=ipsr.read())!=-1){
            System.out.println((char) ch);
        }

        //中
        //国
        ipsr.close();


    }
}

5.字符流写数据的5种方式

采用字符流写数据,并不能直接将数据写入到文件中,它先写在缓冲区,最终通过字节流写入,可以等待刷新后写入文件中;
flush() :刷新流
close():关闭流,在关闭之前先刷新

方法名说明
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)写一个字符串的一部分

6.字符流读数据的2种方式

方法名说明
int read()一次读一个字符数据
int read(char[] cbuf)一次读一个字符数组数据
package Files;

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

public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {

        InputStreamReader ipsr = new InputStreamReader(new FileInputStream("opsw.txt"));

        //一次读一个字符数据
        int ch;
        while ((ch=ipsr.read())!=-1){
            System.out.print((char) ch);  //abcd
        }
        
         //一次读一个字符数组数据

        char[] chs = new char[1024];
        int len;
        while ((len=ipsr.read(chs))!=-1){
            System.out.print(new String(chs,0,len));
    }
}

7.字符缓冲流

字符缓冲流:

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

构造方法:

  • BufferedWriter(Writer out)
  • BufferedReader(Reader in)
package Files;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {

        //字符缓冲流写数据
        
        BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));

        bw.write("hello\r\n");   //换行
        bw.write("world\r\n");
        bw.close();
    }
}

package Files;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class BufferedStreamDemo1 {
    public static void main(String[] args) throws IOException {
        //字符缓冲流写数据

        BufferedReader br = new BufferedReader(new FileReader("bw.txt"));

        //一个字符一个字符读取
        int ch;
        while ((ch=br.read())!=-1){
            System.out.print((char) ch);
        }

        //hello
        //world
//一次读取一个字符数组
        char[] by = new char[1024];
        int len;
        while ((len=br.read(by))!=-1){
            System.out.println(new String(by,0,len));
        }
    }
}

8 字符缓冲流特有功能

  • BufferedWriter:

void newLine():写一行行分隔符,行分隔符字符串由系统属性定义

  • BufferedReader:

public String readLine():读一行文字。
结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null

package Files;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedStreamDemo2 {
    public static void main(String[] args) throws IOException {

        BufferedWriter bwi = new BufferedWriter(new FileWriter("bw.txt"));

        //写数据换行并刷新
        for(int i=0;i<5;i++){
            bwi.write("hello!");
//            bwi.write("\r\n");
            bwi.newLine();      //换行
            bwi.flush();        //刷新
        }

        bwi.close();

    }
}

在这里插入图片描述

package Files;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedStreamDemo3 {
    public static void main(String[] args) throws IOException {

        //一次读一行
        BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
/*
        //第一次读取数据
        String line = br.readLine();
        System.out.println(line);   //hello!
 */
        String line;
        while ((line=br.readLine())!=null){
            System.out.println(line);
        }
        
        br.close();

    }
}

9.案例:集合到文件

需求:
把ArrayList集合中的字符串数据写入到文本文件。要求:每一个字符串元素作为文件中的一行数据
思路:

  • 创建ArrayList集合
  • 往集合中存储字符串元素
  • 创建字符缓冲输出流对象
  • 遍历集合,得到每一个字符串数据
  • 调用字符缓冲输出流对象的方法写数据
  • 释放资源
package Files;

import java.io.*;
import java.util.ArrayList;

public class ArrayToFile {
    public static void main(String[] args) throws IOException {
        //集合到文件
        ArrayList<String> al = new ArrayList<String>();

        al.add("hello!");
        al.add("nihao!");
        al.add("tudou");

        //System.out.println(al);

        BufferedWriter bww = new BufferedWriter(new FileWriter("bww.txt"));

        for(String s:al){
            bww.write(s);
            bww.write("\r");
        }
        bww.close();


    }
}

10.文件到集合

需求:
把文本文件中的数据读取到集合中,并遍历集合。要求:文件中每一行数据是一个集合元素

思路:

  • 创建字符缓冲输入流对象
  • 创建ArrayList集合对象
  • 调用字符缓冲输入流对象的方法读数据
  • 把读取到的字符串数据存储到集合中
  • 释放资源
package Files;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class FileToArray {
    public static void main(String[] args) throws IOException {
        //文件到集合

        BufferedReader brr = new BufferedReader(new FileReader("bww.txt"));

        ArrayList<String> arrayList = new ArrayList<>();

        String line;
        while ((line=brr.readLine())!=null){
            arrayList.add(line);
        }

        System.out.println(arrayList);

        brr.close();

    }
}

11.案例:点名器

需求:
我有一个文件里面存储了班级同学的姓名,每一个姓名占一行,要求通过程序实现随机点名器

思路:

  1. 创建字符缓冲输入流对象
  2. 创建ArrayList集合对象
  3. 调用字符缓冲输入流对象的方法读数据
  4. 把读取到的字符串数据存储到集合中
  5. 释放资源
  6. 使用Random产生一个随机数,随机数的范围在:[0,集合的长度)
  7. 把第6步产生的随机数作为索引到ArrayList集合中获取值
  8. 把第7步得到的数据输出在控制台
package Files;

//点名器

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class CallName {
    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new FileReader("names"));

        ArrayList<String> al = new ArrayList<String>();

        String line;
        while ((line = br.readLine()) != null) {
            al.add(line);
        }
//        System.out.println(al);         //[nini, 土豆, coco, vivi, didi, larry, 龙杰, 老赵, 尼尼, xixi]

        br.close();

        //建立索引
        HashMap<Integer, String> hm = new HashMap<Integer, String>();

        int count = 0;
        for (String s : al) {
            hm.put(count, s);
            count++;

        }
        //创建随机数
        Random rd = new Random();
        int x = rd.nextInt(hm.size());

        //随机点名
        System.out.println(x);
        System.out.println(hm.get(x));
    }
}

12.案例:集合到文件(数据排序改进版)

需求:
键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)。要求按照成绩总分从高到低写入文本文件

格式:姓名,语文成绩,数学成绩,英语成绩
举例:林青霞,98,99,100

思路:

  1. 定义学生类
  2. 创建TreeSet集合,通过比较器排序进行排序
  3. 键盘录入学生数据
  4. 创建学生对象,把键盘录入的数据对应赋值给学生对象的成员变量
  5. 把学生对象添加到TreeSet集合
  6. 创建字符缓冲输出流对象
  7. 遍历集合,得到每一个学生对象
  8. 把学生对象的数据拼接成指定格式的字符串
  9. 调用字符缓冲输出流对象的方法写数据
  10. 释放资源
package Files;

public class Student {

    private String name;
    private int Chinese;
    private int math;
    private int english;

    public Student() {
    }

    public Student(String name, int chinese, int math, int english) {
        this.name = name;
        Chinese = chinese;
        this.math = math;
        this.english = english;
    }

    public String getName() {
        return name;
    }

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

    public int getChinese() {
        return Chinese;
    }

    public void setChinese(int chinese) {
        Chinese = chinese;
    }

    public int getMath() {
        return math;
    }

    public void setMath(int math) {
        this.math = math;
    }

    public int getEnglish() {
        return english;
    }

    public void setEnglish(int english) {
        this.english = english;
    }

    public int gradeSum() {
        return this.getChinese()+this.getEnglish()+this.getMath();
    }
}

package Files;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;

public class ArrayToFileStudent {
    public static void main(String[] args) throws IOException {

        //创建TreeSet集合
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {  //传入比较器
            @Override
            public int compare(Student o1, Student o2) {

                int num = o1.gradeSum()-o2.gradeSum();
                int num1 = num ==0? o1.getChinese()-o2.getChinese():num;
                int num2 = num1 ==0?o1.getMath()-o2.getMath():num1;
                int num3 = num2==0?o1.getName().compareTo(o2.getName()):num2;
                return num3;

            }
        });

        //录入学生数据
        for(int i=0;i<3;i++){
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入学生姓名:");
            String name = sc.nextLine();
            System.out.println("语文成绩");
            int chinese = sc.nextInt();
            System.out.println("数学成绩");
            int math = sc.nextInt();
            System.out.println("英语成绩");
            int english = sc.nextInt();


            //创建学生对象
            Student s = new Student(name,chinese,math,english);

            //将学生对象添加到集合中
            ts.add(s);
        }

        BufferedWriter bw = new BufferedWriter(new FileWriter("studentGrade.txt"));

        for(Student std:ts){
            StringBuilder sb = new StringBuilder();
            sb.append(std.getName()).append(",").append(std.getChinese()).append(",").append(std.getMath()).append(",").append(std.getEnglish());
            bw.write(sb.toString());
            bw.newLine();
            bw.flush();

        }
        bw.close();

    }
}

输入:
在这里插入图片描述
结果:
在这里插入图片描述

56. 特殊操作流

1.标准输入输出流

System类中有两个静态的成员变量:

  • public static final InputStream in:标准输入流。
    通常该流对应于 键盘输入 或由主机环境或用户指定的另一个输入源
  • publicstatic final PrintStream out:标准输出流。
    通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标

//默认字节流,字节流读汉字 返回的是char类型的乱码

自己实现键盘录入数据:

  • BufferedReader br = newBufferedReader(newlnputStreamReader(System.in);

Java就提供了一个类实现键盘录入

  • Scanner sc = new Scanner(System.in);
package Systems;

import java.io.IOException;
import java.io.InputStream;

public class SystemInDemo {
    public static void main(String[] args) throws IOException {
        //标准输入流,数据来源于键盘输入

        InputStream is = System.in;

        int by;
        while ((by=is.read())!=-1){
            System.out.println((char) by);
        }
    }
}

在这里插入图片描述
在这里插入图片描述

package Systems;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class SystemInDemo {
    public static void main(String[] args) throws IOException {
        //标准输入流,数据来源于键盘输入

        InputStream is = System.in;

        //把字节流转换成字符流
        InputStreamReader isr = new InputStreamReader(is);

        int by;
        while ((by=isr.read())!=-1){
            System.out.println((char) by);
        }
    }
}

在这里插入图片描述

一次读取一行汉字
注:一次读取一行是字符缓冲数据流的特有方法

package Systems;

import java.io.*;

public class SystemInDemo {
    public static void main(String[] args) throws IOException {
//        //标准输入流,数据来源于键盘输入
//        InputStream is = System.in;
//        //把字节流转换成字符流
//        InputStreamReader isr = new InputStreamReader(is);
//        //字符缓冲输入流
//        BufferedReader br = new BufferedReader(isr);

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("输入一个字符串:");
        String line = br.readLine();
        System.out.println("您输入的字符床是:"+line);



    }
}

在这里插入图片描述
整数操作

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

//        System.out.print("输入一个字符串:");
//        String line = br.readLine();
//        System.out.println("您输入的字符床是:"+line);

        System.out.println("请输入一个整数:");
        int i = Integer.parseInt(br.readLine());
        System.out.println("您输入的整数是:"+i);

2.标准输出流

输出语句的本质: 是一个标准的输出流
PrintStream ps = System.out;
PrintStream类有的方法,System.out都可以使用

package Systems;

import java.io.PrintStream;

public class SystemOutDemo {
    public static void main(String[] args) {
        //标准输出流
        PrintStream ps = System.out;

        //System.out的本质是字节输出流
        ps.println("hello");
        ps.println(10);
        System.out.println("nihao");
    }
}

3.字节打印流

打印流的分类:

  • 字节打印流:PrintStream
  • 字符打印流: printWriter

打印流的特点:

  • 只负责输出数据,不负责读取数据;
  • 有自己特有的方法

字节打印流

  • PrintStream(String fileName):使用指定的文件名创建新的打印流
  • 使用继承父类的方法写数据,查看的时候会转码;
  • 使用自己的方法(print)查看数据原样输出
package Systems;

import java.io.FileNotFoundException;
import java.io.PrintStream;

public class PrintStreamDemo {
    public static void main(String[] args) throws FileNotFoundException {

        PrintStream ps = new PrintStream("ps.txt");

        //字节输出流有的方法
        ps.write(10);

        //特有方法
        ps.print(25);
        ps.close();
    }
}

4 字符打印流

字符打印流PrintWriter的构造方法:

方法名说明
PrintWriter(String fileName)使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
PrintWriter(Writer out, boolean autoFlush)创建一个新的PrintWriter (out:字符输出流)(autoFlush:一个布尔值,如果为真,则println ,printf,或format方法将刷新输出缓冲区)
package Systems;

import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class PrintWriteDemo {
    public static void main(String[] args) throws IOException {

        PrintWriter pw = new PrintWriter("pw.txt");
        
        pw.write("hello");
        pw.flush();
        //特有方法
        pw.println("nihao");
        pw.flush();
        
        //自动刷新
        PrintWriter pw1 = new PrintWriter(new FileWriter("pw1.txt"),true);
        pw1.println("hello");
        
        pw.close();
        
    }
}

5 对象序列化

对象序列化:
就是将对象保存到磁盘中,或者在网络中传输对象

这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息字节序列写到文件之后,相当于文件中持久保存了一个对象的信息

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化

要实现序列化和反序列化就要使用对象序列化流和对象反序列化流:

  • 对象序列化流:ObjectOutputStream
  • 对象反序列化流:ObjectlnputStream

6.对象序列化流

对象序列化流: ObjectOutputStream

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

构造方法:

  • ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputstream
  • 序列化对象的方法: void writeObject(Object obj):将指定的对象写入ObjectOutputStream

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

package Systems;

import java.io.Serializable;

public class Student implements Serializable {
    private int age;
    private String name;

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

    public Student() {
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

package Systems;

import java.io.*;

public class ObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //对象序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));

        Student s = new Student(10,"nini");

        oos.writeObject(s);

        oos.close();
    }
}

在这里插入图片描述

7.对象反序列化

对象反序列化流:ObjectlnputStream

  • ObjectlnputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象

构造方法:

  • ObjectlnputStream(InputStream
    in):创建从指定的InputStream读取的ObjectInputStream

反序列化对象的方法:

  • Object readObject():从ObjectlnputStream读取一个对象
package Systems;

import java.io.*;

public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //对象反序列化流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));

        Object object = ois.readObject();

        Student s = (Student) object;

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

        ois.close();
    }
}

在这里插入图片描述

8 序列化出现的问题

package Systems;

import java.io.*;

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

        write();
        read();


    }

    //反序列化
    private static void read() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("oos1.txt"));
        Object o = objectInputStream.readObject();
        Student s = (Student) o;
        System.out.println(s.getAge()+","+s.getName());
        objectInputStream.close();

    }

    //序列化
    private static void write() throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("oos1.txt"));
        Student s = new Student(18, "nini");
        objectOutputStream.writeObject(s);
        objectOutputStream.close();

    }
}

Q1:对象序列化一个对象之后,如果修改了对象所属文件,读数据是否出现问题?
当序列化运行时检测到类中的以下问题之一时抛出:

  • 类的串行版本与从流中读取的类描述符的类型不匹配
  • 该类包含未知的数据类型
  • 该类没有可访问的无参数构造函数

所以当我们修改了学生类里的内容时,已经序列化好的文件就会与之不匹配,导致出现问题;

eg:在学生类里添加一个toString方法之后;
在这里插入图片描述

解决方案:给对象所属类一个序列化id值

private static final long serialVersionUID = 42L;

package Systems;

import java.io.Serializable;

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

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

    public Student() {
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "姓名:"+name+","+"年龄:"+age;
    }

}

Q2:如果对象中的某个成员变量不想被序列化,如何实现?

在成员变量处加上修饰符 transient;

在这里插入图片描述

在这里插入图片描述

9.Properties

概述:
是一个Map体系的集合类
Properties可以保存到流中或从流中加载

练习:
Properties作为Map集合的使用

package Maps;

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

public class PropertiesDemo {
    public static void main(String[] args) {
        //Properties 作为Map集合使用
        Properties pp = new Properties();

        pp.put(001,"nini");
        pp.put(002,"coco");
        pp.put(003,"vovo");

        Set<Object> k = pp.keySet();
        for (Object key:k){
            Object value = pp.get(key);
            System.out.println(key+","+value);
        }
    }
}

10.Properties作为集合的特有方法:

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

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

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

        //setProperty(String key,String value):设置集合的键和值 都是String类型的,底层调用HashTable方法put
        pp.setProperty("001","nini");

        System.out.println(pp);   //{001=nini}


        //getPropertiy(String key):根据属性列表的建来获取值
        System.out.println(pp.getProperty("001"));   //nini


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


    }
}

在这里插入图片描述

11.Properties和IO流结合的方法:

方法名说明
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)
void load(Reader reader)从输入字符流读取属性列表((键和元素对)
void store(OutputStream out, String comments)将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
void store(Writer writer,String comments)将此属性列表(键和元素对)写入此Properties表中,以适合使用load(Reader)方法的格式写入输出字符流

需求1:把集合中数据保存到文件
需求2:把文件中数据保存到集合

package Maps;

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

public class PropertiesDemo1 {
    public static void main(String[] args) throws IOException {
        //需求1:把集合中数据保存到文件
        propToFile();
        //需求2:把文件中数据保存到集合
        fileToProp();
    }

    private static void fileToProp() throws IOException {

        Properties pp = new Properties();

        FileReader fr = new FileReader("fw.txt");

        pp.load(fr);
        fr.close();
        System.out.println(pp);
    }

    private static void propToFile() throws IOException {

        Properties prop = new Properties();

        prop.setProperty("1","nini");
        prop.setProperty("2","lili");
        prop.setProperty("3","xixi");

        FileWriter fw = new FileWriter("fw.txt");
        prop.store(fw,null);
        fw.close();
    }
}

集合保存成功
在这里插入图片描述
读取成功:
在这里插入图片描述

Java学习笔记:
笔记1:https://blog.csdn.net/meini32/article/details/122195422
笔记2:https://blog.csdn.net/meini32/article/details/122321446
笔记3:https://blog.csdn.net/meini32/article/details/122381565?spm=1001.2014.3001.5501
笔记4:https://blog.csdn.net/meini32/article/details/122784859

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值