16.File类

File类

File类概述和构造方法

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

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

构造方法

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

Demo

package file;

import java.io.File;

public class FileDemo {
    public static void main(String[] args) {
        // File(String pathname): 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
        File f1 = new File("/Users/ryxiong/develop/vscode/config.py");
        System.out.println(f1);

        // File(String parent, String child): 从父路径字符串和子路径字符串创建新的File实例
        File f2 = new File("/Users/ryxiong/develop/vscode","config.py");
        System.out.println(f2);

        // File(File parent, String child)从父抽象路径名和子路径名字符串创建新的File实例
        File f3 = new File("/Users/ryxiong/develop/vscode");
        File f4 = new File(f3,"config.py");
        System.out.println(f4);
        
        // 输出
        /*
            /Users/ryxiong/develop/vscode/config.py
            /Users/ryxiong/develop/vscode/config.py
            /Users/ryxiong/develop/vscode/config.py
         */
    }
}

File类创建功能

常见方法

方法名 说明
public boolean createNewFile() 当局有该名称的文件不存在时, 创建一个由该路径名的新空文件
public boolean mkdir() 创建由此抽象路径命名的目录
public boolean mkdirs() 创建由次抽象路径命名的目录, 包括任何必须但不存在的父目录

Demo

package file;

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

public class FileDemo2 {
    public static void main(String[] args) throws IOException {
        // 创建java.txt文件
        // public boolean createNewFile(): 当局有该名称的文件不存在时, 创建一个由该路径名的新空文件, 文件不存在返回true, 存在返回false
        File f1 = new File("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/java.txt");
        System.out.println(f1.createNewFile());

        // 创建javaSE目录
        File f2 = new File("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/javaSE");
        System.out.println(f2.mkdir());

        // 创建多级目录 javaEE/java.txt
        File f3 = new File("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/javaEE/java");
        System.out.println(f3.mkdirs());

        File f4 = new File("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/javase.txt");
        System.out.println(f4.mkdir());  // 不能根据名称判断是目录还是文件, 而要根据创建方法来判断

    }

}

File类判断和获取功能

常用方法

方法名 说明
public boolean isDirectory() 判断路径名是否为目录
public boolean isFile() 判断路径是否为文件
public boolean exists() 判断路径是否存在
public String getAbsolutePath() 返回路径的绝对路径字符串
public String getPath() 将路径转换为字符串
public String getName() 返回路径名表示的文件或目录名称
public String[] list() 返回路径表示目录下的文件和目录名称字符串数组
public File[] listFiles() 返回路径表示目录下文件和目录的File对象数组

File类删除功能

  • public boolean delete(): 删除由次抽象路径名表示的文件或目录

相对路径和绝对路径

  • 绝对路径: 完整的目录名
  • 相对路径: 使用取自其他路径名的信息进行解释. 其他路径就是相对路径

Demo

package file;

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

public class FileDemo3 {
    public static void main(String[] args) throws IOException {
        // 创建File对象
        File f = new File("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/java.txt");

        System.out.println(f.isDirectory());
        System.out.println(f.isFile());
        System.out.println(f.exists());

        System.out.println(f.getAbsoluteFile());
        System.out.println(f.getPath());
        System.out.println(f.getName());

        File f2 = new File("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file");
        String[] strArray = f2.list();
        assert strArray != null;
        for (String str: strArray) {
            System.out.println(str);
        }

        File[] fileArray = f2.listFiles();
        assert fileArray != null;
        for(File file: fileArray) {
            // System.out.println(file);
            // System.out.println(file.getName());
            if(file.isFile()) {
                System.out.println(f.getName());
            }
        }

        // public boolean delete(): 删除由次抽象路径名表示的文件或目录
        File f3 = new File("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/java.txt");
        System.out.println(f3.createNewFile());
        System.out.println(f3.delete());
        
        // 如果删除目录下有内容, 需要先删除目录下的内容, 才能删除目录
    }
}

注意:

  • 如果一个目录中有内容,不能直接删除. 需要先删除目录下的内容, 才能删除目录.

递归

递归: 从编程的角度是指方法定义中调用方法本身的现象

递归思路:

  • 讲一个重复的复杂问题, 转化为一个与原问题相似的规模较小的问题来求解
  • 只需要少量的程序可以解决复杂多次的重复计算

递归要解决的两个问题:

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

Demo

package recursion;


public class DiguiDemo {
    public static void main(String[] args) {
        int[] arr = new int[20];

        arr[0] = 1;
        arr[1] = 1;

        for (int i=2; i<arr.length; i++){
            arr[i] = arr[i-1] + arr[i-2];
        }
        System.out.println(arr[19]);
        System.out.println(f(20));
    }

    /*
        递归解决问题, 定义一个方法
            定义方法f(n), 表示第n个月的兔子对数
            第n-1个月的兔子,f(n-1), 第n-2个月的兔子对数f(n-2)
     */

    public static int f(int n) {
        if (n==1 || n==2) {
            return 1;
        } else {
            return f(n-1) + f(n-2);
        }
    }
}

递归获取目下的所有文件的绝对路径

package recursion;

import java.io.File;

public class RecursionDir {
    public static void main(String[] args) {
        // 创建File对象
        File file = new File("/Users/ryxiong/develop/java/javaSE_code/learn_java");

        // 调用方法
        getAllFilePath(file);
    }
    // 定义方法, 用于获取指定目录下的所有内容
    public static void getAllFilePath(File srcFile) {
        // 获取给定的File目录下所有文件或者目录的File数组
        File[] fileArray = srcFile.listFiles();
        if (fileArray != null) {
            for(File file: fileArray) {
                // 判断File对象是否为目录
                if (file.isDirectory()) {
                    // 是: 递归调用
                    getAllFilePath(file);
                } else {
                    // 不是: 获取绝对路径输出
                    System.out.println(file.getAbsoluteFile());
                }
            }
        }
    }
}

字节流

IO概述

  • IO: 输入/输出
  • 流: 一种抽象概念, 是对数据传输的总称.也就是说数据在设备间的传输称为流, 流的本质是数据传输
  • IO流就是用来处理设备间数据传输问题的

IO流分类

按照数据的流向

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

按照数据类型分类

  • 字节流: 字节输入流, 字节输出流
  • 字符流: 字符输入流, 字符输出流

一般来说, 我们的IO流是按照数据类型来分的

字节流抽象基类

  1. intputStream: 字节输入流的所有类的超类
  2. outputStream: 字节输出流的所有类的超类
  3. 子类名特点: 子类名称都是以其父类名作为子类名的后缀

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

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

Demo

package file.IOStream;

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

public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 创建字节输出流对象
        // FileOutputStream(String name): 创建文件输出流就以指定的名称写入文件
        FileOutputStream fos = new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos.txt");
        /*
            做了三件事情:
             1. 创建文件
             2. 创建字节输出流对象
             3. 让字节输出流对象指向文件
         */
        // void write(int b): 将指定的字节写入次文件输出流
        fos.write(97);
        fos.write(57);
        fos.write(55);
        // 最后都要释放资源
        // void close(): 关闭此文件输出流并释放与此流相关联的任何系统资源
        fos.close();
    }
}

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

  • 创建字节流对象
  • 调用write方法写入内容
  • 释放字节流对象资源

字节流写数据3中方式

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

Demo

package file.IOStream;

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

public class FileOutputStreamDemo2 {
    public static void main(String[] args) throws IOException {
        // FileOutputStream(String name): 创建文件输出流以指定的名称写入文件
        FileOutputStream fos = new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos.txt");
        // 这个过程底层实现 new File();

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

        // void write(byte[] b)将b.length字节从指定的字节数组写入此文件输出流, 一次写一个字节数组数据
        byte[] bys = {97,98,99,100};  // 等价于 byte[] bys = "abcd".getBytes();
        fos.write(bys);

        // void write(byte[] b, int off, int len)将len字节从指定的字节数组开始, 从偏移量off开始写入此文件输出流, 一次写一个字节数组的部分数据
        fos.write(bys, 2,2);

        fos.close();
    }
}

两个小问题

  • 实现换行写, 不同系统换行符不一样
    • window: "\r\n"
    • Linux: "\n"
    • Mac: "\r"
  • 实现追加写入
    • Public FileOutputStream(String name, boolean append)
    • 第二个参数为true是, 字节写入文件的末尾而不是开头

Demo

package file.IOStream;

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

public class FileOutputStreamDemo3 {
    public static void main(String[] args) throws IOException {
        // 创建字节流输出对象
        FileOutputStream fos = new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos.txt");
        // 写数据
        for(int i=0; i<10; i++){
            fos.write("hello".getBytes());
            fos.write("\n".getBytes());
        }
        // 释放资源
        fos.close();
        
        // 追加写入实现
        FileOutputStream fos2 =
                new FileOutputStream(
                        "/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos.txt",
                        true
                );

        // 写数据
        for(int i=0; i<10; i++){
            fos2.write("java".getBytes());
            fos2.write("\n".getBytes());
        }
        // 释放资源
        fos2.close();
    }
}

字节流写数据加异常处理

finally: 在异常处理时提供finally块来执行所有清除操作, 比如IO资源的释放

特点: 被finally控制的语句,无论异常有无发生, 一定会执行, 除非JVM退出

格式

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

示例

package file.IOStream;

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

public class FileOutputStreamDemo4 {
    public static void main(String[] args) throws IOException {
        // 创建字节流输出对象
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos.txt");
            // fos = new FileOutputStream("/Users1/fos.txt");  // FileNotFoundException
            // 写数据
            fos.write("hello".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 文件不为空, 则关闭
                assert fos != null;
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

字节流读数据

一次读一个字节数据

FileInputStream: 从文件系统中的文件获取输入字节

  • FileinputStream(String name): 通过打开与实际文件的连接来创建一个FileInputStream, 该文件有文件系统中的路径名name命名

一次读取一个字节方法

  • int read(): 从该输入流读取一个字节的数据

Demo

package file.IOStream;

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

public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 创建对象
        FileInputStream fis = new FileInputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos.txt");
        // 调用读数据方法

        // int read(): 从该输入流读取一个字节的数据
        /*
        // 第一次读取
        int byt = fis.read();
        System.out.println(byt);
        System.out.println((char)byt);

        // 第二次读取
        byt = fis.read();
        System.out.println(byt);
        System.out.println((char)byt);

        // 循环多行读取
        int by = fis.read();
        while (by != -1) {
            System.out.print((char)by);
            by = fis.read();
        }
         */

        // 优化程序, 标准读取代码
        int by;
        while((by=fis.read())!=-1) {
            System.out.print((char)by);
        }
        // 释放资源
        fis.close();
    }
}

CopyDemo赋值文本文件

package file.IOStream;

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

public class CopyDemo {
    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象
        FileInputStream fis = new FileInputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos.txt");
        // 创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos_copy.txt");

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

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

一次读一个字节数组数据

一次读取一个字节数组方法

  • int read(byte[] b): 从该输入流中读取最多b.length个字节的数据到一个字节数组

Demo

package file.IOStream;

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

public class FileInputStreamDemo2 {
    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象
        FileInputStream fis = new FileInputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/fos.txt");

        // 调用字节输入流对象的读取方法
        // int read(byte[] b): 从该输入流中读取最多b.length个字节的数据到一个字节数组
        /*
        byte[] bys = new byte[5]
        // 第一次读
        int len = fis.read(bys);
        System.out.println(len);
        System.out.println(new String(bys));

        // 第二次读
        len = fis.read(bys);
        System.out.println(len);
        System.out.println(new String(bys));

        // 第三次读
        len = fis.read(bys);
        System.out.println(len);
        // String (byte[] bytes, int offset, int length)
        // System.out.println(new String(bys));
        System.out.println(new String(bys,0,len));

         */
        /*
            原文
                hello\r\n
                world\r\n
                read\r\n

            第一次: hello
            第二次: \r\nwor
            第三次: ld\r\n
         */

        // 循环改进
        byte[] bys = new byte[1024];
        int len;
        while ((len=fis.read(bys))!=-1) {
            System.out.println(new String(bys, 0, len));
        }

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

字节缓冲流

字节缓冲流:

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

构造方法:

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

为什么构造方法需要的字节流,而不是文件路径

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

Demo

package file.IOStream;

import java.io.*;

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        // 字节缓冲输出流 BufferedOutputStream(OutputStream out)
        /*
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/bos.txt"));
        // 写数据
        bos.write("hello\r\n".getBytes());
        bos.write("world\r\n".getBytes());

        // 释放资源
        bos.close();
         */
        // 字节缓冲输入流: BufferedInputStream(InputStream out)
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/bos.txt"));
        // 一次读取一个字节
        /*
            int by;
            while ((by=bis.read()) != -1) {
                System.out.print((char)by);
            }
         */
        // 一次读取一个字节数组
        byte[] bys = new byte[1024];
        int len;
        while ((len=bis.read(bys)) != -1) {
            System.out.println(new String(bys, 0, len));
        }

        // 释放资源
        bis.close();
    }
}

视频复制案例

四种复制方式的区别

package file.IOStream.copyAviDemo;

import java.io.*;

public class CopyAviDemo {
    public static void main(String[] args) throws IOException {
        // 记录开始时间
        long startTime = System.currentTimeMillis();

        // 赋值视频
        // method1();  // 共耗时:26604毫秒
        // method2();  // 共耗时:32毫秒
        // method3();  // 共耗时:148毫秒
        method4();  // 共耗时:8毫秒

        // 记录结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("共耗时:" + (endTime - startTime) + "毫秒");
    }

    // 基本字节流一次读写一个字节
    public static void method1() throws IOException  {
        FileInputStream fis = new FileInputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/copyAviDemo/IMG_5934.MOV");
        FileOutputStream fos = new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/copyAviDemo/IMG_5934_copy.MOV");
        int by;
        while ((by=fis.read()) != -1) {
            fos.write(by);
        }
        fis.close();
        fos.close();
    }

    // 基本字节流一次读写一个字节数组
    public static void method2() throws IOException {
        FileInputStream fis = new FileInputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/copyAviDemo/IMG_5934.MOV");
        FileOutputStream fos = new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/copyAviDemo/IMG_5934_copy.MOV");
        byte[] bys = new byte[1024];
        int len;
        while ((len = fis.read(bys)) != -1) {
            fos.write(bys, 0, len);
        }
        fis.close();
        fos.close();
    }

    // 字节缓冲流,一次读写一个字节
    public static void method3() throws IOException {
        BufferedInputStream fis = new BufferedInputStream(new FileInputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/copyAviDemo/IMG_5934.MOV"));
        BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/copyAviDemo/IMG_5934_copy.MOV"));
        int by;
        while ((by = fis.read()) != -1) {
            fos.write(by);
        }
        fis.close();
        fos.close();
    }


    // 字节缓冲流,一次读写一个字节
    public static void method4() throws IOException {
        BufferedInputStream fis = new BufferedInputStream(new FileInputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/copyAviDemo/IMG_5934.MOV"));
        BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("/Users/ryxiong/develop/java/javaSE_code/learn_java/src/file/IOStream/copyAviDemo/IMG_5934_copy.MOV"));
        byte[] bys = new byte[1024];
        int len;
        while ((len = fis.read(bys)) != -1) {
            fos.write(bys, 0, len);
        }
        fis.close();
        fos.close();
    }
}

字符流

字节流操作中文不方便, 提出字符流

  • 字符流 = 字节流 + 编码表

字节流复制中文没有问题, 原因最终是因为底层操作会自动进行字节拼接为中文

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

Demo

package file.IOStream.charStream;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class FileInputStreamDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        // String s = "abc";
        String s = "中国";  // [-28, -72, -83, -27, -101, -67]
        // byte[] bys = s.getBytes();
        // byte[] bys = s.getBytes("UTF-8");  // [-28, -72, -83, -27, -101, -67]
        byte[] bys = s.getBytes("GBK");  // [-42, -48, -71, -6]
        System.out.println(Arrays.toString(bys));
    }
}

编码表

计算机中存储的信息都是二进制表示, 英文,中文,汉字都是二进制转换的结果

按照某种规则, 将字符存储到计算机,称为编码.

反之, 将计算机中的二进制数按照某种规则解析显示出来, 称为解码.

字符集

ASCII字符集: ASCII, 基于拉丁字母的一套编码系统, 用于显示现代英语, 主要包括控制字符和可显示字符.

基本的ASCII字符集,使用7位表示一个字符, 共128字符. ASCII的扩展字符集使用8位表示一个字符, 共256字符, 方便支持欧洲常用字符. 是一个系统支持的所有字符的集合, 包括各国文字, 标点符号, 图形符号, 数字等.

GB系列字符集:

  • GB2312: 简体中文码表.
  • GBK: 最常用的中文码表, 是GB2312表中上的扩展规范, 完全兼容GB2312
  • DB18030: 最新中文码表. 收录汉字70244个, 采用多自己编码, 每个字可由1个, 2个, 4个字节组成.

Unicode字符集

  • 为表达任意语言的任意字符而设计, 业界的统一标准, 称为统一码, 标准万国码.最多使用4个字节的数字来表达每个字母,字符或文字,

  • UTF-8编码: 可以用来表示Unicode标准中任意字符, 他是电子邮件,网页及其其他存储或传送文字的应用中, 优先采用的比那am

    • 编码规则

      128个us-ASCII字符,只需要一个字节编码

      拉丁文等字符, 需要两个字节编码

      大部分常用字(含中文), 使用三个字节编码

      其他极少使用Unicode辅助字符, 使用四字节编码

注意: 采用何种规则编码, 就要采用何种规格解码

字符串中的编码和解码问题

编码:

  • byte[] getBytes(): 使用平台默认字符集将String编码为一些列字节, 结果存储到字节数组
  • byte[] getBytes(String charsetName): 使用指定字符集将String编码为字节,存储到字节数组

解码:

  • String(byte[] bytes): 使用平台默认字符集解码指定的字节数组构造新的String
  • String(byte[] bytes, String charsetName): 指定字符集解码指定的字节数组来构造新的String

Demo

package file.IOStream.charStream;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class EncodeDecode {
    public static void main(String[] args) throws UnsupportedEncodingException {
        // 定义一个字符串
        String s = "中国";

        // byte[] getBytes(): 使用默认字符集编码
        byte[] bys = s.getBytes();  // [-28, -72, -83, -27, -101, -67]
        System.out.println(Arrays.toString(bys));

        // byte[] getBytes(String charsetName): 使用指定字符集将String编码为字节,存储到字节数组
        // byte[] gbys = s.getBytes("UTF-8");  // [-28, -72, -83, -27, -101, -67]
        // byte[] gbys = s.getBytes("GBK");  // [-42, -48, -71, -6]
        // System.out.println(Arrays.toString(gbys));


        // 解码
        // String(byte[] bytes): 使用平台默认字符集解码指定的字节数组构造新的String
        // String s1 = new String(bys);

        //String(byte[] bytes, String charsetName): 指定字符集解码指定的字节数组来构造新的String
        // String s1 = new String(bys, "UTF-8");  // 中国
        String s1 = new String(bys, "GBK");  // 涓浗
        System.out.println(s1);
    }
}

字符流中编码问题

字符流写

  • OutputStreamWriter(OutputStream out) 创建一个默认字符编码的OutputStreamWriter
  • OutputStreamWriter(outputStream out, String charsetName) 创建一个使用命名字符集的OutputStreamWriter

字符流读

  • InputStreamWriter(InputStream out) 创建一个默认字符编码的InputStreamWriter
  • InputStreamWriter(InputStream out, String charsetName) 创建一个使用命名字符集的InputStreamWriter

Demo

package file.IOStream.charStream;

import java.io.*;

public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException {
        // OutputStreamWriter(OutputStream out) 创建一个默认字符编码的OutputStreamWriter
        // OutputStreamWriter(outputStream out, String charsetName) 创建一个使用命名字符集的OutputStreamWriter

        // 创建对象
        // FileOutputStream fos = new FileOutputStream("./osw.txt");
        // OutputStreamWriter osw = new OutputStreamWriter(fos);
        // OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./learn_java/src/file/IOStream/charStream/osw.txt"));
        // OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./learn_java/src/file/IOStream/charStream/osw.txt"), "UTF-8");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./learn_java/src/file/IOStream/charStream/osw.txt"), "GBK");
        osw.write("中国");
        osw.close();

        // InputStreamWriter(InputStream out) 创建一个默认字符编码的InputStreamWriter
        // InputStreamWriter(InputStream out, String charsetName) 创建一个使用命名字符集的InputStreamWriter

        InputStreamReader isr = new InputStreamReader(new FileInputStream("./learn_java/src/file/IOStream/charStream/osw.txt"));
        // 一次读取一字节
        int ch;
        while ((ch=isr.read()) != -1) {
            System.out.print((char)ch);
        }
        isr.close();
    }
}

字符流写数据5中方式

方法名 说明
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() 关闭流, 释放资源, 关闭前会刷新流, 关闭后无法继续写数据

Demo

package file.IOStream.charStream;

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

public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        // OutputStreamWriter(OutputStream out): 创建一个默认字符编码的OutputStreamWriter

        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./learn_java/src/file/IOStream/charStream/osw2.txt"));

        // void write(int c): 写入一个字符
        /*
        osw.write(97);
        // void flush() 刷新流
        osw.flush();
        osw.write(98);
        osw.flush();
        osw.write(99);

         */

        // void write(char[] cbuf): 写入一个字符数组
        /*
        char[] chs = {'a', 'b', 'c', 'd', 'e'};
        osw.write(chs);

         */

        // void write(char[] cbuf, int off, int len): 写入字符数组的一部分
        /*
        char[] chs = {'a', 'b', 'c', 'd', 'e'};
        // osw.write(chs, 0, chs.length);
        osw.write(chs, 1, 3);

         */

        // void write(String str)写一个字符串
        // osw.write("abcde");

        // void write(String str, int off, int len)写一个字符串的一部分
        osw.write("abcde", 1, 3);

        // 关闭资源
        osw.close();  // 在关闭之前会调用一次flush方法
    }
}

字符流读数据2中方式

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

Demo

package file.IOStream.charStream;

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

public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        // InputStreamReader(InputStream in): 创建一个默认字符编码的InputStreamReader
        InputStreamReader isr = new InputStreamReader(new FileInputStream("./learn_java/src/file/IOStream/charStream/osw2.txt"));

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

         */

        // int read(char[] cbuf): 一次读一个字符组数据
        char[] chs = new char[1024];
        int len;
        while ((len=isr.read(chs))!=-1){
            System.out.println(new String(chs, 0, len));
        }

        // 释放资源
        isr.close();
    }
}

复制java文件

Demo

package file.IOStream.charStream;

import java.io.*;

public class CopyJavaDemo {
    public static void main(String[] args) throws IOException {
        // 创建字符输入流对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream("./learn_java/src/file/IOStream/charStream/ConversionStreamDemo.java"));

        // 创建字符输出流对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./learn_java/src/file/IOStream/charStream/ConversionStreamDemo_copy.java"));

        // 读写数据, 复制文件
        // 一次读写一个字符数据
        /*
        int ch;
        while ((ch=isr.read())!=-1) {
            osw.write(ch);
        }

         */

        // 一次读写一个字符数组
        char[] chs = new char[1024];
        int len;
        while ((len=isr.read(chs))!=-1) {
            osw.write(chs, 0, len);
        }

        // 释放资源
        osw.close();
        isr.close();

    }
}

改进版本

  • FileReader(String filename): 继承InputStreamReader,读取文件字符的便捷类

  • FileWriter(String filename): 继承OutputStreamWriter, 写入字符文件的便捷类

Demo

package file.IOStream.charStream;

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

public class FileReaderDemo {
    public static void main(String[] args) throws IOException {
        // 新建文件字符读取类
        FileReader fr = new FileReader("./learn_java/src/file/IOStream/charStream/osw.txt");

        // 新建文件字符写入类
        FileWriter fw = new FileWriter("./learn_java/src/file/IOStream/charStream/osw_copy.txt");
        // 读写数据, 复制文件
        /*
        int ch;
        while ((ch=fr.read())!=-1){
            fw.write(ch);
        }
         */

        // 一次一个字符数组
        char[] chs = new char[1024];
        int len;
        while ((len=fr.read(chs)) != -1) {
            fw.write(chs, 0, len);
        }

        fr.close();
        fw.close();
    }
}

字符缓冲流

字符缓冲流

  • BufferedWriter(Writer out): 将文本写入字符输出流, 缓冲字符, 已提供单个字符, 数组和字符串的高效写入, 可以指定缓冲区大小, 或默认大小,默认值足够大, 可用于大多数用途.
  • BufferedReader(Reader in): 从字符输入流读取文本, 缓冲字符, 以提供字符, 数组和行的高效读取,

Demo

package file.IOStream.charStream;

import java.io.*;

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        // BufferWriter(Writer out)
        BufferedWriter bw = new BufferedWriter(new FileWriter("./learn_java/src/file/IOStream/charStream/bw.txt"));
        bw.write("hello\r\n");
        bw.write("world\r\n");
        bw.write("java");

        bw.close();

        // BufferedReader(Reader in)
        BufferedReader br = new BufferedReader(new FileReader("./learn_java/src/file/IOStream/charStream/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.println(new String(chs, 0, len));
        }
        br.close();

    }
}

字符缓冲流特有功能

BufferedWriter

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

BufferedReader

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

Demo

package file.IOStream.charStream;

import java.io.*;

public class BufferedStreamDemo2 {
    public static void main(String[] args) throws IOException {
        // 创建字符缓冲输出流
        BufferedWriter bw = new BufferedWriter(new FileWriter("./learn_java/src/file/IOStream/charStream/bw2.txt"));
        // 写数据
        for(int i=0; i<3; i++) {
            bw.write("hello" + i);
            // bw.write("\r\n");
            bw.newLine();
            bw.flush();
        }
        // 释放资源
        bw.close();

        // BufferReader
        BufferedReader br = new BufferedReader(new FileReader("./learn_java/src/file/IOStream/charStream/bw2.txt"));

        // public String readLine(): 读一行数据
        /*
        String line = br.readLine();
        System.out.println(line);

        line = br.readLine();
        System.out.println(line);

        line = br.readLine();
        System.out.println(line);

        line = br.readLine();
        System.out.println(line);

         */
        // 循环改进
        String line;
        while ((line=br.readLine())!=null) {
            System.out.println(line);
        }

        br.close();
    }
}

最常用文件复制案例

package file.IOStream.charStream;

import java.io.*;

public class CopyJavaDemo2 {
    public static void main(String[] args) throws IOException {
        // 创建字符缓冲流输入对象
        BufferedReader br = new BufferedReader(new FileReader("learn_java/src/file/IOStream/charStream/bw.txt"));
        // 创建字符缓冲流输出对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("learn_java/src/file/IOStream/charStream/bw_copy.txt"));

        // 读取数据, 复制文件
        // 使用字符缓冲流特有功能实现
        String line;
        while ((line=br.readLine())!=null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 释放资源
        bw.close();
        br.close();

    }
}

IO流小结

  • 字节流

image-20201021144251551

  • 字符流

image-20201021144352917

多级目录复制案例

demo

package file.IOStream;

import java.io.*;

public class multiLevelCopy {
    public static void main(String[] args) throws IOException {
        // 创建数据源File对象:
        File srcFile = new File("learn_java/srcFile");
        // 创建目的地File对象
        File destFile = new File("learn_java/destFile");
        // 写方法实现文件夹的复制, 参数为数据源File对象和目的地File对象
        copyFolder(srcFile, destFile);
    }

    private static void copyFolder(File srcFile, File destFile) throws IOException {
        // 判断数据源File是否为目录
        if (srcFile.isDirectory()) {
            // 在目录下创建和数据源File一样的目录
            String srcFileName = srcFile.getName();
            File newFolder = new File(destFile, srcFileName);
            if (!newFolder.exists()) {
                newFolder.mkdir();
            }

            // 获取数据源File下所有文件或者目录的File数组
            File[] fileArray = srcFile.listFiles();
            // 遍历File数组, 得到每一个file对象
            assert fileArray != null;
            for(File file: fileArray) {
                // 把改File作为数据源file对象, 递归调用复制文件夹的方法
                copyFolder(file, newFolder);
            }
        } else {
            // 说明是文件, 直接复制
            File newFile = new File(destFile, srcFile.getName());
            copyFile(srcFile, newFile);
        }
    }

    private static void copyFile(File srcFile, File destFile) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
        byte[] bys = new byte[1024];
        int len;
        while ((len=bis.read(bys))!=-1) {
            bos.write(bys, 0, len);
        }
        bis.close();
        bos.close();
    }

    //
}

复制文件异常处理

Demo

package file.IOStream;

import java.io.*;

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

    }

    // 文件复制异常处理
    // try ... catch ... finally
    private static void copyFile(File srcFile, File destFile) throws IOException {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            fr = new FileReader(srcFile);
            fw = new FileWriter(destFile);
            char[] chs = new char[1024];
            int len;
            while ((len=fr.read(chs))!=-1) {
                fw.write(chs, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fr!=null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fw!=null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // JDK7改进方案
    private static void copyFile2(File srcFile, File destFile) {
        try {
            FileReader fr = new FileReader(srcFile);
            FileWriter fw = new FileWriter(destFile);
            char[] chs = new char[1024];
            int len;
            while ((len=fr.read(chs))!=-1) {
                fw.write(chs, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // JDK9改进方案
    private static void copyFile3(File srcFile, File destFile) throws IOException {
        FileReader fr = new FileReader(srcFile);
        FileWriter fw = new FileWriter(destFile);
        try(fr; fw) {
            char[] chs = new char[1024];
            int len;
            while ((len=fr.read(chs))!=-1) {
                fw.write(chs, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

特殊操作流程

标准输入输出流

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

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

标准输入流

自己实现键盘录入:

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

自己实现键盘录入太麻烦,java提供了一个类供调用

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

Demo

package file.IOStream;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;

public class SystemInDemo {
    public static void main(String[] args) throws IOException {
        // public static final InputStream in: 标准输入流
        InputStream is = System.in;
        /*

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

        // 如何把字节流转换为字符流
        // InputStreamReader isr = new InputStreamReader(is);
        // 使用字符流每次读一行, 字符缓冲输入流的特有方法
        // BufferedReader br = new BufferedReader(isr);
        // 改进
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入一个字符串");
        String line = br.readLine();
        System.out.println("输入的字符串是:" + line);

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

        // 自己实现键盘录入太麻烦,java提供了一个类供调用
        Scanner sc = new Scanner(System.in);

    }
}

标注输出流

Demo

package file.IOStream;

import java.io.PrintStream;

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

        // 能够方便地打印各种数据值
        /*
        ps.print("hello");
        ps.print(100);
        ps.print("\r\n");
        ps.println("hello");
        ps.println(100);
         */

        // System.out的本质是一个字节数出流
        System.out.println("hello");
        System.out.println(100);
    }
}

打印流

打印流特点:

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

打印流特点:

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

字节打印流

  • PrintStream(String fileName): 使用指定的文件名创建新的打印流

  • 如果继承父类的方法写数据, 查看的时候会转码, 如果使用自己特有的方法写数据, 查看的数据原样输出

Demo

package file.IOStream;

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

public class PrintStreamDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // PrintStream(String fileName): 使用指定的文件名创建新的打印流
        PrintStream ps = new PrintStream("learn_java/ps.txt");
        // 写数据
        ps.write(97);

        // 使用特有方法写
        ps.print(97);
        ps.print(98);
        ps.println(97);
        ps.println(98);

        // 释放资源
        ps.close();
    }
}

字符打印流

PrintWriter的构造方法

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

Demo

package file.IOStream;

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

public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
        // PrintWriter(String fileName): 使用指定文件名新的PrintWriter, 而不需要自动执行刷新
        PrintWriter pw = new PrintWriter("learn_java/pw.txt");
        /*
        pw.write("hello");
        pw.write("\r\n");
        pw.flush();

        pw.write("hello");
        pw.write("\r\n");
        pw.flush();

         */

        pw.println("hello");
        /*
            pw.write("hello");
            pw.write("\r\n");
         */
        pw.flush();

        // PrintWriter(Writer out, boolean autoFlush)
        PrintWriter pw2 = new PrintWriter(new FileWriter("learn_java/pw2.txt"), true);
        pw2.println("hello");  // 实现了自动刷新
        // 相当于
        /*
            pw.write("hello");
            pw.write("\r\n");
            pw.flush();
         */
        pw.close();
        pw2.close();
    }
}

赋值文件打印流改进

package file.IOStream;

import java.io.*;

public class CopyPrintWriterDemo {
    public static void main(String[] args) throws IOException {
        /*
        // 根据数据源创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("learn_java/pw.txt"));
        // 根据目的地创建字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("learn_java/pw_copy.txt"));

        // 读写数据
        String line;
        while ((line=br.readLine())!=null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 释放资源
        bw.close();
        br.close();

         */

        // 根据数据源创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("learn_java/pw.txt"));
        // 根据目的地创建字符输出流对象
        PrintWriter pw = new PrintWriter(new FileWriter("learn_java/pw_copy.txt"));
        // 读写数据
        String line;
        while ((line=br.readLine())!=null) {
            pw.println(line);
        }

        // 释放资源
        pw.close();
        br.close();
    }
}

对象序列化流

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

这种机制就是使用一个字节序列表示一个对象, 该字节序列包括: 对象的类型, 对象的数据和对象中存储的属性等信息

相当于文件中持久保存了一个对象的信息.

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

对象序列化流

ObjectOutputStream: 将java对象的原始数据类型和图形写入OutputStream, 实现对象持久存储.如果流失网络套接字流, 则可以在另一个主机上或另一个进程中重构对象

构造方法:

  • ObjectOutputStream(OutputStream out): 创建一个写入指定OutputStream的ObjectOutputStream

序列化方法

  • void writeObject(Object obj): 将指定的对象写入ObjectOutputStream

注意:

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

Student

package file.objectStream;

import java.io.Serializable;

public class Student implements Serializable {  // 需要实现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;
    }

}

Demo

package file.objectStream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/*
    NotSerializableException: 对象序列化需要该类实现java.io.Serializable接口. 序列化运行时或实例的类可能会抛出异常
    java.io.Serializable, 不实现此接口的类不会使任何状态序列化或反序列化
 */

public class ObjectOutputStreamDemo {

    public static void main(String[] args) throws IOException {
        // ObjectOutputStream(OutputStream out): 创建一个写入指定OutputStream的ObjectOutputStream
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("learn_java/oos.txt"));

        // 创建对象
        Student s = new Student("林青霞",33);

        // void writeObject(Object obj): 将指定的对象写入ObjectOutputStream
        oos.writeObject(s);

        // 释放资源
        oos.close();
    }
}

对象反序列化流

ObjectInputStream

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

构造方法

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

反序列化对象的方法:

  • Object readObject(): 从ObjectInputStream中读取一个对象

Demo

package file.objectStream;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // ObjectInputStream(InputStream in): 创建从指定的InputStream读取的
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("learn_java/oos.txt"));

        // Object readObject(): 从ObjectInputStream读取一个对象
        Object obj = ois.readObject();
        
        Student s = (Student) obj;
        System.out.println(s.getName() + "," + s.getAge());
        // 释放资源
        ois.close();
    }
}

对象序列化流三个问题

对象序列化一个对象后, 加入修改了类文件, 反序列化会不会出问题?

  • 会抛出: java.io.InvalidClassException: file.objectStream.Student;

如果出问题了, 如何解决

  • 给对象所属类, 添加一个值serialVersionUID: private static final long serialVersionUID = 42L;

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

  • 用transient关键字修饰该成员变量, 标记的成员变量不会参与序列化过程

Student

package file.objectStream;

import java.io.Serializable;

public class Student implements Serializable {  // 需要实现Serializable接口才能序列化
    private static final long serialVersionUID = 42L;
    private String name;
    // private int age;
    private transient int age;  // 被transient修饰的变量,不会被序列化

    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 +
                '}';
    }

     */
}

Demo

package file.objectStream;

import java.io.*;
/*
    对象序列化一个对象后, 加入修改了类文件, 反序列化会不会出问题?
        java.io.InvalidClassException: file.objectStream.Student;
            当序列化检测如下问题之一抛出
                类的串行版本与从流中读取的类描述符的类型不匹配
                该类包含未知的数据类型
                该类没有可访问的无参构造函数
            local class incompatible:
                stream classdesc serialVersionUID = -1673330068761390418,
                local class serialVersionUID = 4736309558144996041

    如果出问题了, 如何解决
        给对象所属类, 添加一个值: private static final long serialVersionUID = 42L;
    如果一个对象中的某个成员变量的值不想被序列化, 如何实现
        用transient修饰该变量,不会被序列化
 */

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

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

Properties

继承自Map集合

package file.objectStream;

import java.util.Properties;
import java.util.Set;
/*
    properties作为Map集合使用
 */
public class PropertiesDemo {
    public static void main(String[] args) {
        // 创建集合对象
        Properties prop = new Properties();

        // 存储元素
        prop.put("01", "林青霞");
        prop.put("02", "张曼玉");
        prop.put("03", "王祖贤");

        // 遍历集合
        Set<Object> keySet = prop.keySet();
        for (Object key: keySet) {
            Object value = prop.get(key);
            System.out.println(key + "," + value);
        }
    }
}

特有方法

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

Demo

package file.objectStream;

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

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

        // Object setProperty(String key, String value): 设置集合的键和值, 都是String类型, 底层调用hashtable方法put
        prop.setProperty("01", "林青霞");
        prop.setProperty("02", "张曼玉");
        prop.setProperty("03", "王祖贤");

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

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

    }
}

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)方法的格式写入输出字符流

Demo

package file.objectStream;

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

public class PropertiesDemo3 {
    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("learn_java/properties.txt");
        prop.load(fr);
        fr.close();
        System.out.println(prop);
    }

    private static void myStore() throws IOException {
        Properties prop = new Properties();
        prop.setProperty("01", "林青霞");
        prop.setProperty("02", "张曼玉");
        prop.setProperty("03", "王祖贤");

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

posted @ 2020-10-28 13:04  ryxiong728  阅读(95)  评论(0编辑  收藏  举报