10—IO流

File对象

概述 

File类在包java.io.File下,代表操作系统的文件对象(文件、文件夹)

File类提供了诸如:定位文件、获取文件本身信息、删除文件、创建文件(文件、文件夹)等功能

创建File对象的方式

public File(String pathname)  根据文件路径创建文件对象

pulbic File(String parent,String child)  从父路径名字符串或子路径名字符串创建对象

public File(File parent,String child)  根据父路径对应文件对象和子路径字符串创建文件对象

package com.spark.study;

import java.io.File;

/**
 * FileDemo class
 * description: file对象创建
 *
 * @author Administrator
 * @date 2023/4/30
 */
public class FileDemo {
    public static void main(String[] args) {
        // 根据路径创建File对象,绝对路径
        File file = new File("D:\\IDEA 2020\\workplaces\\io-study\\src\\data.txt");
        // 该文件路径对应的文件对象是否存在
        System.out.println(file.exists());
        // 文件字节大小
        System.out.println(file.length());

        // 根据路径创建File对象,相对路径
        File file2 = new File("io-study\\src\\data.txt");
        // 判断该路径对应的文件对象是否存在
        System.out.println(file2.exists());
        // 文件字节大小
        System.out.println(file2.length());

    }
}

常用方法 

判断文件类型、获取文件信息功能

  • boolean isDirectory()  判断File对象是否是文件夹
  • boolean isFile()  判断File对象是否是文件
  • boolean exists()  判断File是否存在
  • String getAbsolutePath()  返回File的绝对路径
  • String getPath()  返回File定义时的路径
  • String getName()  返回File对象的文件或文件夹名称
  • long getModified()  返回文件最后修改时间 
package com.spark.study;

import java.io.File;
import java.text.SimpleDateFormat;

/**
 * FileApi class
 * description: File类对象的常用方法
 *
 * @author Administrator
 * @date 2023/4/30
 */
public class FileApi {
    public static void main(String[] args) {
        // 创建File对象
        File file = new File("src/data.txt");
        // 判断路径对应的文件或文件夹是否存在
        System.out.println(file.exists());
        // 判断File对象是否为文件
        System.out.println(file.isFile());
        // 判断File对象是否为路径
        System.out.println(file.isDirectory());
        // 获取File对象的绝对路径
        System.out.println(file.getAbsolutePath());
        // 获取File对象定义时的路径
        System.out.println(file.getPath());
        // 获取File对象的字节大小
        System.out.println(file.length());
        // 获取File对象的名称
        System.out.println(file.getName());
        // 获取文件最后修改时间
        System.out.println(file.lastModified());
        // 获取文件最后修改时间,格式化
        System.out.println("文件最后修改时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));
    }
}

创建和删除功能

  • boolean createNewFile()  创建一个新的空文件
  • boolean mkdir()  创建一级文件夹
  • boolean mkdirs()  创建多级文件夹
  • boolean delete()  删除空文件夹 

delete方法直接删除不走回收站;如果删除的是一个文件,并且文件没有被占用则直接删除;delete方法默认只能删除空文件夹。 

package com.spark.study;

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

/**
 * FileApi2 class
 * description: 创建和删除
 *
 * @author Administrator
 * @date 2023/4/30
 */
public class FileApi2 {
    public static void main(String[] args) throws IOException {
        File file = new File("tempfiles/a.txt");
        // 创建新文件
        System.out.println(file.createNewFile());
        // 删除文件
        System.out.println(file.delete());

        File file2 = new File("tempfiles/aaa");
        // 创建一级目录
        System.out.println(file2.mkdir());
        // 删除空目录
        System.out.println(file2.delete());

        File file3 = new File("tempfiles/bbb/ccc");
        // 创建多级目录
        System.out.println(file3.mkdirs());
    }
}

遍历功能

  • String [] list()  获取当前目录下的所有一级文件夹名称到一个字符数组中去
  • File [] listFiles()  获取当前目录下的所有一级文件对象到一个文件对象数组中去 
package com.spark.study;

import java.io.File;

/**
 * FileApi3 class
 * description: 遍历功能
 *
 * @author Administrator
 * @date 2023/4/30
 */
public class FileApi3 {
    public static void main(String[] args) {
        File file = new File("tempfiles/");
        // 获取指定目录下一级文件名称到字符数组中
        String[] list = file.list();
        for (String s : list) {
            System.out.println(s);
        }
        // 获取指定目录下所有一级文件对象到File数组中
        File[] files = file.listFiles();
        for (File f : files) {
            System.out.println(f.getAbsolutePath());
        }
    }
}

listFiles()方法注意事项

  • 当调用者不存在时,返回null
  • 当调用者是一个文件时,返回null
  • 当调用者是一个空文件夹时,返回一个长度为0的数组
  • 当调用者是一个有内容的文件夹时,将里面所有的文件和文件夹路径存放到File数组中返回
  • 当调用者是一个有隐藏文件的文件夹时,将里面所有的文件和文件夹路径存放到File数组中返回,包含隐藏内容
  • 当调用者是一个需要权限才能进入的文件夹时,返回null 

方法递归

形式和特点 

方法直接调用自己或者间接调用自己的形式称为方法递归 

递归作为一种算法在程序设计语言中广泛使用 

递归的形式

  • 直接递归:自己调用自己
  • 间接递归:方法调用其他方法,其他方法又回调方法自己 

流程和核心要素 

需求:计算1-n的阶乘,使用递归思想解决 

① 阶乘公式:f(n) = 1*2*3*4*...*(n-1)*n

② 公式等价形式:f(n) = f(n-1)*n

③ 如果求1-5的阶乘

f(5) = f(4) * 5

f(4) = f(3) * 4

f(3) = f(2) * 3

f(2) = f(1) * 2

f(1) = 1

package com.spark.recursion;

/**
 * Test class
 * description: 1-n的阶乘
 *
 * @author Administrator
 * @date 2023/5/1
 */
public class Test {
    public static void main(String[] args) {
        System.out.println(test(5));
    }
    public static int test(int n){
        if(n==1){
            return 1;
        }
        return test(n-1) * n;
    }
}

核心要素:

  • 递归的公式
  • 递归的终结点
  • 递归的方向必须走向终结点 

递归案例 

猴子吃桃问题:猴子第一天摘下若干桃子,当即吃了一半,觉得不够,于是又吃了一个;第二天又吃了前一天的一半,觉得不够,于是又吃了一个;以后每天都是吃前一天剩余桃子数量一半,觉得不够又多吃一个;到了第10天发现桃子只剩一个,请问猴子第一天摘了多少桃子

① 递归的公式:f(n) = ( f(n+1) + 1) * 2   ====>   f(n) = 2*f(n+1) + 2

② 递归的终点:f(10) = 1

package com.spark.recursion;

/**
 * Test2 class
 * description: 猴子吃桃问题
 *
 * @author Administrator
 * @date 2023/5/1
 */
public class Test2 {
    public static void main(String[] args) {
        System.out.println(f(10));
        System.out.println(f(1));
        System.out.println(f(2));
    }
    public static int f(int n){
        if(n==10){
            return 1;
        }
        return 2*f(n+1) + 2;
    }

}

非规律化递归案例——文件搜索

从本地磁盘中,搜索出某个文件名称并输出绝对路径

① 先定位一级文件对象

② 遍历全部一级对象判断是否是文件

③ 如果是文件判断是否是搜索的文件名

④ 如果是文件夹,进入继续递归重复上述过程 

package com.spark.recursion;

import java.io.File;

/**
 * Test3 class
 * description: 文件搜索
 *
 * @author Administrator
 * @date 2023/5/1
 */
public class Test3 {
    public static void main(String[] args) {
        File dir = new File("D:\\JAVA");
        searchFile(dir,"IO流.md");
    }
    public static void searchFile(File dir, String fileName){
        // 判断是否是目录
        if(dir!=null && dir.isDirectory()){
            // 获取一级对象
            File[] files = dir.listFiles();
            // 判断files是否为空
            if(files!=null && files.length>0){
                // 遍历
                for (File file : files) {
                    // file是文件就判断名称是否是查询的名称
                    if(file.isFile()){
                        if(file.getName().contains(fileName)){
                            System.out.println("文件找到了:"+file.getAbsolutePath());
                        }
                    }else{
                        // 递归查找,重复上述操作
                        searchFile(file,fileName);
                    }
                }
            }
        }else{
            System.out.println("指定的路径不是目录,无法查找!");
        }
    }
}

 字符集

当需要不同的字符集时,如何使用代码来完成编码和解码操作?

① 编码

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

② 解码

  • String (byte [] bytes)  使用平台的默认字符集解码指定的字节数组来构造新的String
  • String (byte [] bytes,String charsetName)  通过指定的字符集解码指定的字节数组来构造新的String 
package com.spark.charset;

import java.util.Arrays;

/**
 * Test class
 * description: 字符集编码和解码
 *
 * @author Administrator
 * @date 2023/5/1
 */
public class Test {
    public static void main(String[] args) throws Exception {
        String str = "我爱你China";
        // 使用默认字符集进行编码 UTF-8
        byte[] bytes = str.getBytes();
        System.out.println(bytes.length);
        System.out.println(Arrays.toString(bytes));

        // 使用指定字符集进行编码 GBK
        byte[] gbks = str.getBytes("GBK");
        System.out.println(gbks.length);
        System.out.println(Arrays.toString(gbks));

        // 使用系统默认字符集进行解码
        String s1 = new String(bytes);
        System.out.println(s1);
        String s2 = new String(gbks); // 乱码
        System.out.println(s2);
        // 使用指定字符集进行解码
        String s3 = new String(gbks,"GBK");
        System.out.println(s3);
    }
}

IO流概述

IO流是输入、输出流用于读写数据

I表示input,是数据从磁盘文件中读取到内存的过程,称之为输入,负责读操作

O表示output,是内存程序的数据从内存写入到磁盘文件的过程,称之为输出,负载写操作

IO流的分类

① 按照流的方向分为输入流和输出流

② 按照流中的数据最小单位分为字节流和字符流

使用场景:

  • 字节流适合做一切文件数据的拷贝(音视频、文本)
  • 字节流不适合读取中文内容输出
  • 字符流适合文本文件的操作(读、写) 

字节流基本用法 

① 文件字节输入流——每次读取一个字节

流程:

  • 创建FileInputStream对象建立与源文件的链接
  • 通过read方法每次读取一个字节 
package com.spark.input;

import java.io.FileInputStream;
import java.io.InputStream;

/**
 * Test class
 * description: 文件字节输入流——每次读取一个字节
 *
 * @author Administrator
 * @date 2023/5/1
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 创建FileInputStream对象
        InputStream inputStream = new FileInputStream("src/data.txt");
        // 每次读取一个字节
        int read;
        while((read=inputStream.read())!=-1){
            System.out.print((char)read);
        }
    }
}

存在的弊端:

  • 每次只能一个一个字节去读取,效率慢
  • 无法避免中文乱码问题 

② 文件字节输入流——每次读取一个字节数组 

流程:

  • 创建FileInputStream对象
  • 使用read(byte [] buffer) 方法每次读取一个字节数组
package com.spark.input;

import java.io.FileInputStream;
import java.io.InputStream;

/**
 * Test2 class
 * description: 文件字节输入流——每次读取一个字节数组长度
 *
 * @author Administrator
 * @date 2023/5/1
 */
public class Test2 {
    public static void main(String[] args) throws Exception {
        // 创建FileInputStream对象
        InputStream inputStream = new FileInputStream("src/data.txt");
        // 创建字节数组
        byte [] buffer = new byte[3];
        int len;
        while((len = inputStream.read(buffer)) != -1) {
            System.out.print(new String(buffer,0,len));
        }
    }
}

存在的弊端:虽然提升了读取效率,但是依然无法避免中文乱码问题

③ 文件字节输入流——一次读完全部字节

过程:

  • 创建FileInputStream对象建立与源文件的链接
  • 创建字节数组,长度为源文件中字节的长度一次性读取完毕
package com.spark.input;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

/**
 * Test3 class
 * description: 文件字节输入流——一次性读取全部
 *
 * @author Administrator
 * @date 2023/5/1
 */
public class Test3 {
    public static void main(String[] args) throws Exception {
        // 创建FileInputStream对象
        File file = new File("src/data.txt");
        InputStream inputStream = new FileInputStream(file);
        // 创建字节数组,长度为源文件字节长度
        byte [] buffer = new byte[(int)file.length()];
        System.out.println("文件字节数:"+inputStream.read(buffer));
        System.out.println(new String(buffer));
    }
}

存在的弊端:虽然可以解决中文乱码问题,但是当文件过大时可能会出现内存溢出

JDK9提供了一次性读取全部字节的API——readAllBytes() 

④ 文件字节输出流——写字节数据到文件

流程:

  • 创建FileOutputStream对象
  • 调用write方法写出数据
  • 刷新数据
  • 释放资源 
package com.spark.output;

import java.io.FileOutputStream;
import java.io.OutputStream;

/**
 * Test class
 * description: 文件字节输出流
 *
 * @author Administrator
 * @date 2023/5/2
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 创建FileOutputStream对象
        // 向文件中写内容以追加的形式
        //OutputStream outputStream = new FileOutputStream("src/outdata.txt",true);

        // 默认每次向文件中写内容时先清空数据
        OutputStream outputStream = new FileOutputStream("src/outdata.txt");

        // 向文件中写入一个字节
        outputStream.write('a');
        outputStream.write('b');
        outputStream.write('c');
        // 换行
        outputStream.write("\r\n".getBytes());

        // 向文件中写入一个字节数组
        outputStream.write("我爱你中国".getBytes());
        // 换行
        outputStream.write("\r\n".getBytes());

        // 刷新数据
        outputStream.flush();
        // 释放资源
        outputStream.close(); // 释放资源会自动刷新数据
    }
}

文件拷贝 

字节流支持一切文件类型的复制,使用字节流复制文件的流程:

  • 创建文件字节输入流链接源文件
  • 创建文件字节输出流输出到目标文件
  • 定义一个字节数组用于读取存储字节数据
  • 释放资源 
package com.spark.output;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Test2 class
 * description: 文件的拷贝
 *
 * @author Administrator
 * @date 2023/5/2
 */
public class Test2 {
    public static void main(String[] args) throws Exception {
        // 1.创建文件字节输入流
        InputStream inputStream = new FileInputStream("src/outdata.txt");
        // 2.创建文件字节输出流
        OutputStream outputStream = new FileOutputStream("src/newout.txt");
        // 3.定义一个字节数组
        byte [] buffer = new byte[1024];
        // 读取数据
        int len;
        while((len = inputStream.read(buffer))!=-1){
            outputStream.write(buffer, 0, len);
        }
        // 4.释放资源
        outputStream.close();
        inputStream.close();
    }
}

 资源释放方式

try-catch-finally 

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

特点: 被finally控制的语句最终一定会执行,除非JVM退出

语法格式:

try{
    // 执行语句
}catch(Exception e){
    // 捕获到异常
}finally{
    // 最终执行语句
}

使用try-catch-finally语句块释放IO流资源

package com.spark.resource;

import java.io.*;

/**
 * TryCatchFinally class
 * description: try catch finally释放IO流资源
 *
 * @author Administrator
 * @date 2023/5/2
 */
public class TryCatchFinally {
    public static void main(String[] args) {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            // 1.创建文件字节输入流
            inputStream = new FileInputStream("src/outdata.txt");
            // 2.创建文件字节输出流
            outputStream = new FileOutputStream("src/newout.txt");
            // 3.定义一个字节数组
            byte[] buffer = new byte[1024];
            // 读取数据
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 4. 释放资源
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

try-catch-resources 

由于try-catch-finally方式手动释放资源的方式过于繁琐,JDK7对释放资源进行了优化

package com.spark.resource;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * TryWithResource class
 * description: try with resource 释放IO流资源
 *
 * @author Administrator
 * @date 2023/5/2
 */
public class TryWithResource {
    public static void main(String[] args) {
        try (
                // 这里只能放置资源对象,用完会自动调用close关闭资源
                // 即使出现BUG也会做关闭操作
                // 1.创建文件字节输入流
                InputStream inputStream = new FileInputStream("src/outdata.txt");
                // 2.创建文件字节输出流
                OutputStream outputStream = new FileOutputStream("src/newout.txt");
        ) {
            // 3.定义一个字节数组
            byte[] buffer = new byte[1024];
            // 读取数据
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

字符流基本用法 

① 文件字符输入流——一次读取一个字符

过程:

  • 创建文件字符输入流FileReader对象
  • 读出一个字符 
package com.spark.input;

import java.io.FileReader;
import java.io.Reader;

/**
 * Test4 class
 * description: 文件字符输入流——一次读取一个字符
 *
 * @author Administrator
 * @date 2023/5/2
 */
public class Test4 {
    public static void main(String[] args) throws Exception {
        // 创建文件字符输入流
        Reader reader = new FileReader("src/data.txt");
        // 每次读取一个字符
        int read;
        while((read = reader.read()) != -1){
            System.out.print((char)read);
        }
    }
}

② 文件字符输入流——一次读取一个字符数组

过程:

  • 创建文件字符输入流FileReader
  • 创建字符数组,用于存储读取到的字符数据
  • 读取数据 
package com.spark.input;

import java.io.FileReader;
import java.io.Reader;

/**
 * Test5 class
 * description: 文件字符输入流——一次读取一个字符数组
 *
 * @author Administrator
 * @date 2023/5/2
 */
public class Test5 {
    public static void main(String[] args) throws Exception {
        // 创建文件字符输入流
        Reader reader = new FileReader("src/data.txt");
        // 创建一个字符数组进行接收
        char [] buffer = new char[1024];
        // 读取数据
        int len;
        while((len = reader.read(buffer))!=-1){
            String str = new String(buffer,0,len);
            System.out.print(str);
        }
    }
}

③ 文件字符输出流

过程:

  • 创建文件字符输出流FileWriter对象
  • 输出字符到目标文件 
package com.spark.output;

import java.io.FileWriter;
import java.io.Writer;

/**
 * Test3 class
 * description: 文件字符输出流
 *
 * @author Administrator
 * @date 2023/5/2
 */
public class Test3 {
    public static void main(String[] args) throws Exception {
        // 创建文件字符输出流
        Writer writer = new FileWriter("src/newout2.txt");
        // 写字符追加方式
        //Writer writer = new FileWriter("src/newout2.txt",true);

        // 写一个字符
        writer.write(97);
        writer.write('b');
        // 换行
        writer.write("\r\n");

        // 写一个字符串
        writer.write("我爱你中国");
        // 换行
        writer.write("\r\n");

        // 写一个字符数组
        writer.write("我爱你中国".toCharArray());
        // 换行
        writer.write("\r\n");

        // 写一个字符串一部分
        writer.write("abcdefg",1,4);
        // 换行
        writer.write("\r\n");

        // 写一个字符数组一部分
        writer.write("Java从入门到放弃".toCharArray(),0,4);
        
        // 释放资源
        writer.close();
    }
}

缓冲流 

缓冲流也称为高效流、高级流。缓冲流自带缓冲区,可以提高原始字节流、字符流读写数据的性能。

缓冲字节流 

缓冲字节输入流:BufferedInputStream

缓冲字节输出流:BufferedOutputStream

缓冲字节流性能优化原理:缓冲字节输入输出流自带了8KB缓冲池,读取数据时,直接从缓冲池中读取数据;写数据时,数据直接输出到缓冲池中,所以性能较好

缓冲字节流的基本用法

package com.spark.buffer;

import java.io.*;

/**
 * Test class
 * description: 缓冲字节流
 *
 * @author Administrator
 * @date 2023/5/9
 */
public class Test {
    public static void main(String[] args) {
        try(
                // 包装原字节输入流为缓冲输入流
                InputStream in = new BufferedInputStream(new FileInputStream("src/data.txt"));
                // 包装原字节输出流为缓冲输出流
                OutputStream out = new BufferedOutputStream(new FileOutputStream("src/newdata.txt"));
                ){
            int len;
            byte [] buffer = new byte[1024];
            while((len = in.read(buffer))!=-1){
                out.write(buffer,0,len);
            }
            System.out.println("文件复制成功...");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

缓冲字符流   

字符缓冲输入流:BufferedReader

字符缓冲输出流:BufferedWriter

缓冲字符流的基本用法

package com.spark.buffer;

import java.io.*;

/**
 * Test2 class
 * description: 字符缓冲流
 *
 * @author Administrator
 * @date 2023/5/9
 */
public class Test2 {
    public static void main(String[] args) {
        try(
                // 包装原始字符输入流为字符缓冲输入流
                Reader reader = new BufferedReader(new FileReader("src/outdata.txt"));
                // 包装原始字符输出流为字符缓冲输出流
                Writer writer = new BufferedWriter(new FileWriter("src/outdata3.txt"));
                ){
            int len;
            char [] buffer = new char[1024];
            while((len = reader.read(buffer))!=-1){
                writer.write(buffer,0,len);
            }
            System.out.println("文件复制成功");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

 转换流 

当文件的编码与代码的编码不一致时,使用字符流读取文本内容依然会出现乱码情况,这时就需要使用转换流进行读写数据

字符输入转换流:InputStreamReader

字符输出转换流:InputStreamWriter

解决读取文件乱码

  • 可以提取文件的原始字节流,原始字节不会存在问题
  • 把字节流以指定的编码转换成字符输入流,这样字符输入流的字符就不会乱码了 
package com.spark.changestream;

import java.io.*;

/**
 * Test class
 * description: 解决字符流读取不同编码文件乱码
 *
 * @author Administrator
 * @date 2023/5/13
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 链接GBK编码文件
        InputStream in = new FileInputStream("D:\\test.txt");
        // 将字节流转换为字符流
        //Reader isr = new InputStreamReader(in); // 默认以UTF-8编码,读取依然乱码
        Reader reader = new InputStreamReader(in,"GBK"); // 指定编码
        int len;
        char [] buffer = new char[1024];
        while((len = reader.read(buffer)) != -1){
            String str = new String(buffer,0,len);
            System.out.print(str);
        }
    }
}

解决以指定的编码写到文件中

package com.spark.changestream;

import java.io.*;

/**
 * Test2 class
 * description: 以指定编码将数据写入到文件中
 *
 * @author Administrator
 * @date 2023/5/13
 */
public class Test2 {
    public static void main(String[] args) throws Exception {
        OutputStream out = new FileOutputStream("D:\\data2.txt");
        // 使用转换流,以指定编码将数据写入文件
        Writer writer = new OutputStreamWriter(out,"GBK");
        // 将低级流转换为高级流
        BufferedWriter os = new BufferedWriter(writer);
        // 写入数据
        os.write("我爱你中国1~");
        // 换行
        os.newLine();
        os.write("我爱你中国2~");
        os.close();
    }
}

序列化对象 

对象序列化:以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化

使用到的流是对象字节输出流:ObjectOutputStream

package com.spark.serializable;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

/**
 * Test class
 * description: 对象序列化
 *
 * @author Administrator
 * @date 2023/5/13
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 创建字节流链接文件
        OutputStream out = new FileOutputStream("src/obj.txt");
        // 创建对象字节输出流
        ObjectOutputStream os = new ObjectOutputStream(out);
        // 创建对象
        Student student = new Student("张三",22);
        os.writeObject(student);
        os.close();
    }
}

对象反序列化:以内存为基准,把存储在磁盘文件中的对象数据恢复成内存中的对象

使用到的流是对象字符输入流:ObjectInputStream

package com.spark.serializable;

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

/**
 * Test2 class
 * description: 对象反序列化
 *
 * @author Administrator
 * @date 2023/5/13
 */
public class Test2 {
    public static void main(String[] args) throws Exception {
        // 创建对象字节输入流包装低级流链接文件
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("src/obj.txt"));
        // 读取文件中的对象
        Student student = (Student) in.readObject();
        System.out.println(student);
    }
}

拓展:当对象中的某些字段不想让其序列化时,比如:密码等重要信息,可以使用transient修饰属性

public class User implements Serializable{
    private String name;
    private transient String password;
}

打印流 

打印流可以实现方便、高效的打印数据到文件中去。打印流一般指:PrintStream,PrintWrite两个类可以实现打印什么数据就是什么数据

PrintStream

构造器:

  • public PrintStream(OutputStream os) 打印流直接通向字节输出流管道

  • public PrintStream(File f) 打印流直接通向文件对象

  • public PrintStream(String filePath) 打印流直接通向文件路径

方法:

  • print() 打印任意类型的数据出去 

PrintWriter

构造器:

  • public PrintWriter(OutputStream os) 打印流直接通向字节输出流管道

  • public PrintWriter(Writer w) 打印流直接通向字符输出流管道

  • public PrintWriter(File f) 打印流直接通向文件对象

  • public PrintWriter(String filePath) 打印流直接通向文件路径

方法:

  • print() 打印任意类型的数据出去 
package com.spark.print;

import java.io.FileWriter;
import java.io.PrintStream;
import java.io.PrintWriter;

/**
 * Test class
 * description: 打印流
 *
 * @author Administrator
 * @date 2023/5/13
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 创建打印流
        PrintStream ps = new PrintStream("src/print.txt");
        ps.println("我爱你中国");
        ps.println(123456);
        ps.println('a');
        ps.println(true);
        ps.close();

        // 创建打印流
        //PrintWriter pw = new PrintWriter("src/print.txt");
        // 如果需要追加内容,在低级流中指定为追加方式
        PrintWriter pw = new PrintWriter(new FileWriter("src/print.txt",true));
        pw.println("我爱你中国2");
        pw.println(123);
        pw.println('b');
        pw.println(false);
        pw.close();
    }
}

PrintSteam和PrintWriter区别:

  • 打印数据功能上是一模一样,都是使用方便,性能高效(核心优势)
  • PrintStream继承自字节输出流OutputStream,支持写字节数据的方法
  • PrintWriter继承自字符输出流Writer,支持写字符数据 

补充知识:Properties 

Properties其实就是一个Map集合,继承自HashTable,但是一般不会当集合使用,而是用于将对象中的键值对信息存储到属性文件中去

作用:

  • Properties代表的是一个属性文件,可以将自己对象中的键值对信息写入到一个属性文件中去
  • 属性文件:后缀是.properties结尾的文件,里面的内容都是key=value,后续做系统配置信息的 例如框架中的application.properties 

方法:

  • void load(Reader reader) 从输入字符流读取属性列表
  • void load(InputStream inputStream) 从输入字节流读取属性列表
  • void stroe(OutputStream out , String comments) 将此属性列表写入此properties表中,以适合于使用load方法写入输出字节流

  • void store(Writer writer , String comments) 将此属性列表写入此properties表中,以适合于使用load方法写入输出字符流

  • Object setProperty(String key , String value) 保存键值对 (put)

  • Object getProperty(String key) 通过key获取属性值 (get) 

package com.spark.properties;

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

/**
 * Test class
 * description: Properties
 *
 * @author Administrator
 * @date 2023/5/13
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 创建Properties对象
        Properties properties = new Properties();
        // 设置 key value
        properties.setProperty("name","张三");
        properties.setProperty("password","123456");
        // 将 key value写入到属性文件中
        properties.store(new FileWriter("src/user.properties"),"这个是用户相关的信息");

        // 加载属性文件
        properties.load(new FileReader("src/user.properties"));
        // 根据key获取value
        String name = properties.getProperty("name");
        String password = properties.getProperty("password");
        System.out.println("name=" + name+" password=" + password);

        // 获取属性文件中所有的key
        Set<String> keys = properties.stringPropertyNames();
        keys.forEach(key -> System.out.println(key));
    }
}

补充知识:IO框架 

commons-io是apache开源基金组织提供的一组有关io操作的类库,可以提高IO功能开发的效率。

commons-io工具包提供了很多有关io操作的类,有两个主要的类FileUtils,IOUtils

FileUtils主要有如下方法:

  • String readFileToString(File file,String encoding) 读取文件中的数据,返回字符串

  • void copyFile(File srcFile, File destFile) 复制文件

  • void copyDirectoryToDirectory(File srcDir, File destDir) 复制文件夹

  • void copyFileToDirectory(File file , File dir) 复制文件到指定文件夹

  • void delete(File file) 删除指定文件

  • void deleteDirectory(File dir) 删除指定文件夹

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值