java 基础IO盘点,系统讲解常用IO

本文深入讲解Java IO流的基础概念及各类流的操作方法,包括文件与目录处理、字节流与字符流的应用技巧、对象流的序列化与反序列化过程等。通过丰富的示例代码帮助读者掌握Java IO流的核心知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看到b站韩顺平老师发了IO,自己也没系统总结过IO,写篇文章记录一下吧
源码(码云):所有测试代码https://gitee.com/yin_zhipeng/learn_the_basics_of_java_io/tree/master/src/main/java
文件流
  1. 文件在程序中以流形式来操作
    在这里插入图片描述
  2. 流:数据在数据源(文件)和程序(内存)之间经历的路径
  1. 输入流:(往程序输入的流)数据从数据源(文件)到程序(内存)的路径
  2. 输出流:(程序往外输出的流)数据从程序(内存)到数据源(文件)的路径
Java IO流
  1. I/O(Input/Output),I/O技术,处理数据传输,例如读写文件,网络通讯
  2. java中数据的输入/输出以“流(stream)”的方式进行
  3. java.io包下提供"流"类和接口,用以获取不同种类的数据,通过方法输入或输出数据
流的分类
  1. 按操作数据单位不同:字节流(8bit二进制位,无损);字符流(按字符操作):记住,二进制文件例如图片、音频、视频等用字节流,不要用字符流。避免不必要的错误发生。
  2. 数据流流向不同:输入流、输出流
  3. 按流的角色不同:节点流、处理流/包装流
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
节点流和处理流
  1. 节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter[源码]
    在这里插入图片描述
  2. 处理流(包装流),连接已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,如BufferedReader、BufferedWriter[源码],他们可以提供内部缓冲区数组
    在这里插入图片描述
  1. 性能提高:以增加缓冲的方式提高输入输出效率
  2. 操作便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便
  3. 处理流只需要关闭外层流即可(关处理流,会自动将它作用的节点流一起关掉)
对象流,多用于序列化和反序列化的处理流
  1. 假设我们想让Dog dog = new Dog(“黄狗蛋”,3)这个对象持久化到磁盘,并能从文件中恢复对象,就需要用到对象流(ObjectInputStream/ObjectOutputStream)和序列化/反序列化操作
  2. 序列化就是保存数据时,保存数据的值和数据类型
  3. 反序列化就是恢复数据时,恢复数据的值和数据类型
  4. 类想要可序列化,需要让其支持序列化,实现Serializable接口(空接口,标记作用,标记对象可被序列化)或Externalizable(继承Serializable,并声明了两个方法(读和写),一般不用)
  5. 实现Serializable接口,最好要生成一个serialVersionUID。是序列化前后的唯一标识符,相当于密钥,序列化时,会根据这个ID序列化,否则会自动生成,一旦修改,后期恢复,因为ID不同,会反序列化失败

一、文件与目录

1. 创建文件

类图:basics_of_java_io/uml/File.puml

在这里插入图片描述

new File(String pathname)//根据路径构建一个File对象
new File(File parent,String child)//根据父目录文件+子路径构建
new File(String parent,String child)//根据父目录+子路径构建
//上面只是将文件搞到内存,下面方法才是写到磁盘中
createNewFile()方法 创建新文件
测试:basics_of_java_io/file/FileCreateTest.java

在这里插入图片描述

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

/**
 * 文件创建
 */
public class FileCreateTest {
    public static void main(String[] args) {
        FileCreateTest fileCreateTest = new FileCreateTest();
        fileCreateTest.createByPathName("E:\\news1.txt");// 方式一
        fileCreateTest.createByParentChild();//方式二
        fileCreateTest.createByParentChildPath();//方式三
    }

    // 方式一、new File(String pathname)
    public void createByPathName(String pathname){
        File file = new File(pathname);
        try {
            boolean newFile = file.createNewFile();
            System.out.println(pathname+"文件创建完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //方式二、new File(File parent,String child) //根据父目录文件+子路径构建
    //E:\\父目录,news2.txt子路径
    public void createByParentChild(){
        File file = new File(new File("E:\\"), "news2.txt");//文件创建在内存

        try {
            boolean newFile = file.createNewFile();//写到磁盘
            System.out.println(file.getAbsolutePath()+"文件创建完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //方式三、new File(String parent,String child) //根据父目录路径+子路径构建
    public void createByParentChildPath(){
        File file = new File("E:\\", "news3.txt");
        try {
            boolean newFile = file.createNewFile();
            System.out.println(file.getAbsolutePath()+"文件创建完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. 获取文件信息

描述(🍅:不常用/🏆:常用)API
🏆获取文件名String getName()
🏆获取文件绝对路径String getAbsolutePath()
🏆获取当前file的父路径String getParent()
🏆获取file长度Long length()
🏆文件是否存在boolean exists()
🏆是否是文件boolean isFile()
🏆是否为目录boolean isDirectory()
测试:basics_of_java_io/file/FileInformation.java

在这里插入图片描述

import java.io.File;

/**
 * 文件信息
 */
public class FileInformation {
    public static void main(String[] args) {
        File file = new File("E:/news1.txt");
        System.out.println("\uD83C\uDFC6获取文件名:"+file.getName());
        System.out.println("\uD83C\uDFC6获取文件绝对路径:"+file.getAbsolutePath());
        System.out.println("\uD83C\uDFC6获取当前file的父路径:"+file.getParent());
        System.out.println("\uD83C\uDFC6获取file长度:"+file.length());
        System.out.println("\uD83C\uDFC6文件是否存在:"+file.exists());
        System.out.println("\uD83C\uDFC6是否是文件:"+file.isFile());
        System.out.println("\uD83C\uDFC6是否为目录:"+file.isDirectory());

    }
}

3. 操作目录

java中目录也被当做文件

描述(🍅:不常用/🏆:常用)API
🏆创建一级目录boolean mkdir()
🏆创建多级目录boolean mkdirs()
🏆删除空目录或指定fileboolean delete()
测试:basics_of_java_io/file/DirectoryOperationTest.java

在这里插入图片描述

import java.io.File;

/**
 * 目录操作
 */
public class DirectoryOperationTest {
    public static void main(String[] args) {
        File file = new File("E:/testDirectory/news1.txt");
        if(!file.exists()){//如果路径不存在
            //file.createNewFile();//如果路径不存在,会报错
            //如果目录不存在,并且是一级目录,会创建目录,和文件
            //file.mkdir();//我们这里是两级,这个创建会失败
            file.mkdirs();//如果目录不存在,无论几级目录,都创建多级目录和文件
            System.out.println("\uD83C\uDFC6mkdirs()创建成功:"+file.getAbsolutePath());
        }
        System.out.println("\uD83C\uDFC6delete()删除指定文件:"+file.delete());
    }
}

二、字节输入流

1. FileInputStream文件输入流

描述(🍅:构造方法/🏆:普通方法)API
🍅通过打开一个到实际文件的连接创建一个FileInputStream,该文件通过文件系统中的File对象file指定FileInputStream(File file)
🍅通过使用文件描述符fdObj创建一个FileInputStream,该文件描述符表示到文件系统中某个实际文件的现有连接FileInputStream(FileDescriptor fdObj)
🍅通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径名name指定FileInputStream(String name)
🏆返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。int available()
🏆关闭此文件输入流并释放与此流有关的所有系统资源void close()
🏆确保在不再引用文件输入流时调用其close方法protected void finalize()
🏆返回与此文件输入流有关的唯一FileChannel对象FileChannel get Channel()
🏆返回表示到文件系统中实际文件的连接的FileDescriptor对象,该文件系统正被此FileInputStream使用FileDescriptor getFD()
🏆从此输入流中读取一个数据字节int read()
🏆从此输入流中将最多b.length个字节的数据读入一个byte数组中int read(byte[] b)
🏆从此输入流中将最多len个字节的数据读入一个byte数组中int read(byte[] b,int off,int len)
🏆从输入流中跳过并丢弃n个字节的数据long skip(long n)
for example(举例),news1.txt文件内容读取:basics_of_java_io/io_stream/input_stream/FileInputStreamTest.java

在这里插入图片描述

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

/**
 * 文件字符输入流FileInputStream
 */
public class FileInputStreamTest {
    public static void main(String[] args) {
        FileInputStreamTest fileInputStreamTest = new FileInputStreamTest();
        try {
            System.out.println("============================使用read()方法读==============================");
            fileInputStreamTest.readTest();
            System.out.println("============================使用read(byte)方法读==============================");
            fileInputStreamTest.readByByteTest();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //使用read()方法读,从输入流读取一个字节(保存在int型变量中),没有输入可用,此方法将阻止
    //如果返回-1,表示读取完毕
    public void readTest() throws IOException {
        String filePath = "E:/news1.txt";
        FileInputStream fileInputStream = new FileInputStream(filePath);//创建FileInputStream对象,用于读取文件
        int readData = 0;//保存read()方法每次读出的字节
        while((readData = fileInputStream.read())!=-1){
            System.out.print((char)readData);//这种形式中文会乱码,因为中文是3个字节,char类型2个字节,强转后,会丢二进制位
        }
        System.out.println();
        //关闭流
        fileInputStream.close();
    }
    //使用read(byte[])方法读,读出btye.length个字节,放到byte中,没有输入可用,此方法将阻止
    //如果返回-1,表示读取完毕。否则返回实际读取到的字节数
    public void readByByteTest() throws IOException {
        String filePath = "E:/news1.txt";
        FileInputStream fileInputStream = new FileInputStream(filePath);//创建FileInputStream对象,用于读取文件
        int byteCount = 0;//用来保存read(bytes)每次读出的字节数
        byte[] bytes = new byte[1024];
        while((byteCount=fileInputStream.read(bytes))!=-1){
            System.out.println("当前数组实际读出的字节数:"+byteCount);
            System.out.print(new String(bytes));
        }
        System.out.println();
        //关闭流
        fileInputStream.close();
    }
}

2. BufferedInputStream缓冲字节输入流

字节处理流:底层拥有缓冲数组,提高效率;用缓冲流获取news2.txt文本数据(会乱码,不推荐处理文本文件):basics_of_java_io/io_stream/input_stream/BufferedInputStreamTest.java

在这里插入图片描述

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

public class BufferedInputStreamTest {
    public static void main(String[] args) {
        BufferedInputStreamTest bufferedInputStreamTest = new BufferedInputStreamTest();
        try {
            bufferedInputStreamTest.test();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void test() throws IOException {
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("E:/news2.txt"));

        int dataCount = 0;
        byte[] bytes = new byte[10];
        while ((dataCount = bufferedInputStream.read(bytes))!=-1){
            System.out.print(new String(bytes,0,dataCount));
        }
    }
}

三、字节输出流

1. FileOutputStream文件输出流

描述(🍅:构造方法/🏆:普通方法)API
🍅创建向指定file,写入数据的文件输出流FileOutputStream(File file)
🍅创建向指定file写入数据的文件输出流,并可以指定是否采用追加方式(输出内容到文件末尾追加)FileOutputStream(File file,boolean append)
🍅创建向指定文件描述符处写入数据的文件输出流FileOutputStream(FileDescriptor fdObj)
🍅创建一个向指定名称文件中写入数据的文件输出流FileOutputStream(String name)
🍅创建一个向指定名称文件中写入数据的文件输出流,可选追加FileOutputStream(String name,boolean append)
🏆关闭此文件输出流并释放与此流有关的所有系统资源void close()
🏆清理文件的连接,确保不再引用此文件输出流时调用此流的close方法protected void finalize()
🏆返回与此文件输出流有关的唯一FileChannel对象FileChannel getChannel()
🏆返回与此流有关的文件描述符FileDescriptor getFD()
🏆将b.length个字节从指定byte数组写入此文件输出流中void write(byte[] b)
🏆将指定byte数组中从偏移量off开始的len个字节写入此文件输出流void write(byte[] b,int off,int len)
🏆将指定字节写入此文件输出流void write(int b)
for example(举例),输出news1.txt内容到news2.txt文件,将文件复制到testDirectory文件夹(注意文件不存在会自动创建,但必须确保目录存在):basics_of_java_io/io_stream/input_stream/FileInputStreamTest.java

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

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

/**
 * 文件字符输出流FileOutputStream
 */
public class FileOutputStreamTest {
    public static void main(String[] args) {
        FileOutputStreamTest fileOutputStreamTest = new FileOutputStreamTest();
        try {
//            fileOutputStreamTest.test();
//            fileOutputStreamTest.test2();
            fileOutputStreamTest.test3();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //输出内容到news2.txt文件
    public void test() throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("E:/news2.txt");

        FileInputStream fileInputStream = new FileInputStream("E:/news1.txt");
        byte[] bytes = new byte[1024];
        System.out.println("从news1.txt文件读取内容:");
        while(fileInputStream.read(bytes)!=-1){
            System.out.print(new String(bytes));
            //输出
            fileOutputStream.write(bytes);

        }
        System.out.println("写入完成");
        fileInputStream.close();
        fileOutputStream.close();
    }
    //追加内容到news2.txt文件
    public void test2() throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("E:/news2.txt",true);

        FileInputStream fileInputStream = new FileInputStream("E:/news1.txt");
        byte[] bytes = new byte[1024];
        System.out.println("从news1.txt文件读取内容:");
        while(fileInputStream.read(bytes)!=-1){
            System.out.print(new String(bytes));
            //输出
            fileOutputStream.write(bytes);

        }
        System.out.println("追加完成");
        fileInputStream.close();
        fileOutputStream.close();
    }
    //将news2.txt文件拷贝到testDirectory文件夹下
    public void test3() throws IOException {
        FileInputStream fileInputStream = new FileInputStream("E:/su.jfif");
        FileOutputStream fileOutputStream = new FileOutputStream("E:/testDirectory/su.jfif");

        int byteCount = 0;
        byte[] bytes = new byte[1024];
        while((byteCount = fileInputStream.read(bytes))!=-1){
            fileOutputStream.write(bytes,0,byteCount);//读出多少,就写入多少,否则会写多
        }
        System.out.println("复制E:/su.jfif文件到E:/testDirectory/su.jfif成功");
        if(fileInputStream != null){
            fileInputStream.close();
        }
        if(fileOutputStream !=null){
            fileOutputStream.close();
        }

    }
}

2. BufferedOutputStream缓冲字节输出流

字节处理流:将多个字节写入底层输出流中,不必对每次字节写入,都调用底层系统:复制jins.jpg文件

在这里插入图片描述

import java.io.*;

public class BufferedOutputStreamTest {
    public static void main(String[] args) {
        BufferedOutputStreamTest bufferedOutputStreamTest = new BufferedOutputStreamTest();
        try {
            bufferedOutputStreamTest.test1();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void test1() throws IOException {
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("E:/jins.jpg"));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("E:/copy.jpg"));

        System.out.println("将E:/jins.jpg复制到E:/copy.jpg");
        //读数据
        int dataCount = 0;
        byte[] bytes = new byte[1024];
        while((dataCount = bufferedInputStream.read(bytes))!=-1){
            bufferedOutputStream.write(bytes,0,dataCount);
        }
        bufferedOutputStream.close();
        bufferedInputStream.close();
    }
}

四、字符输入流

1. FileReader文件字符输入流

描述(🍅:构造方法/🏆:普通方法)API
🍅创建指定file的文件字符输入流FileReader(File file)
🍅创建指定路径的文件字符输入流FileReader(String name)
🏆读取单个字符,返回字符int值(char可以自动转换int),到文件末尾返回-1int read()
🏆批量读取多个字符到数组,返回读取到的字符数,到文件末尾,返回-1int read(char[])
描述(🍅:构造方法/🏆:普通方法)API
🏆将char[]转换成Stringnew String(char[])
🏆将char[]的指定部分转换成Stringnew String(char[],off,len)
for example(举例),将如下news3.txt中内容,读取:basics_of_java_io/io_stream/reader/FileReaderTest.java

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

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

public class FileReaderTest {
    public static void main(String[] args) {
        try {
            FileReaderTest fileReaderTest = new FileReaderTest();
//            fileReaderTest.test1();
            fileReaderTest.test2();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * read()方法读取单个字符
     */
    public void test1()throws IOException{
        FileReader fileReader = new FileReader("E:/news3.txt");
        int data = 0;//保存单个字符的数据
        while((data = fileReader.read())!=-1){
            System.out.print((char)data);
        }
    }
    //使用字符数组读取
    public void test2()throws IOException{
        FileReader fileReader = new FileReader("E:/news3.txt");
        int dataCount = 0;//保存读取的字符数
        char[] bytes = new char[10];
        while((dataCount = fileReader.read(bytes))!=-1){
            System.out.print(new String(bytes,0,dataCount));
        }
    }
}

2. BufferedReader缓冲字符输入流

BufferedReader处理流,连接已存在的流(节点流或处理流)之上,关闭时,会自动将作用的节点流关掉:basics_of_java_io/io_stream/reader/BufferedReaderTest.java

在这里插入图片描述

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

/**
 * 字符缓冲输入流
 */
public class BufferedReaderTest {
    public static void main(String[] args) {
        BufferedReaderTest bufferedReaderTest = new BufferedReaderTest();
        try {
            bufferedReaderTest.test1();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //BufferedReader处理流封装FileReader节点流
    public void test1() throws IOException {
        System.out.println("=====>>>\uD83C\uDFC6BufferedReader处理流封装FileReader节点流,read()方法读取news4中文本,每次读一个字符\uD83C\uDFC6<<<======");

        BufferedReader bufferedReader = new BufferedReader(new FileReader("E:/news3.txt"));

        int data = 0;//读出字符的二进制,转换成int型
        while((data =  bufferedReader.read())!=-1){
            System.out.print(((char) data));
        }
        bufferedReader.close();
        System.out.println("=====>>>\uD83C\uDFC6BufferedReader处理流封装FileReader节点流,read(char[],int,int)方法读取news4中文本,每次读一个字符\uD83C\uDFC6<<<======");

        BufferedReader bufferedReader2 = new BufferedReader(new FileReader("E:/news3.txt"));
        char[] chars = new char[10];
        int dataCount = 0;//读出的字符个数
        while((dataCount =  bufferedReader2.read(chars))!=-1){
            System.out.print(new String(chars,0,dataCount));
        }
        bufferedReader2.close();

        System.out.println("==高效===>>>\uD83C\uDFC6readLine()方法读取,每次读一行,遇到换行符就认为一行读完,但是换行符不会读取\uD83C\uDFC6<<<======");

        BufferedReader bufferedReader3 = new BufferedReader(new FileReader("E:/news3.txt"));

        String readLine = "";

        while((readLine = bufferedReader3.readLine())!=null){
            System.out.println(readLine);
        }

        bufferedReader3.close();
    }
}

关处理流,为什么会自动帮我们关闭节点流呢?

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

五、字符输出流

1. FileWriter文件字符输出流

描述(🍅:构造方法/🏆:普通方法)API
🍅创建指定file的文件字符输出流,覆盖模式,每次写入都从文件的开头位置写FileWriter(File file)
🍅创建指定路径的文件字符输出流,覆盖模式,每次写入都从文件的开头位置写FileWriter(String name)
🍅创建指定file的文件字符输出流,追加模式,每次写入都从文件末尾写FileWriter(File file,boolean)
🍅创建指定路径的文件字符输出流,追加模式,每次写入都从文件末尾写FileWriter(String name,boolean)
🏆写入单个字符write(int)
🏆写入指定数组write(char[])
🏆写入指定数组的指定部分write(char[],off,len)
🏆写入整个字符串write(string)
🏆写入字符串的指定部分write(string,off,len)
需要用到的StringAPI
描述(🍅:构造方法/🏆:普通方法)API
🏆将String转换成char[]toCharArray()
注意事项
  1. FileWriter使用后,需要关闭close或刷新flush
  2. 否则写入不到指定文件(实际底层写入文件的逻辑,再flush()和close()中调用)
for example(举例),向news4.txt文件写入"打扫宿舍!2!3asdf":basics_of_java_io/io_stream/writer/FileWriterTest.java

在这里插入图片描述

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

public class FileWriterTest {
    public static void main(String[] args) {
        FileWriterTest fileWriterTest = new FileWriterTest();
        try {
            fileWriterTest.test1();
            fileWriterTest.test2();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //字符写
    public void test1() throws IOException {
        FileWriter fileWriter = new FileWriter("E:/news4.txt");
        String str = "打扫宿舍!2!3asdf";
        char[] chars = str.toCharArray();
        for(char c : chars){
            fileWriter.write(c);
        }
        System.out.println("打扫宿舍!2!3asdf=====>>>已写入到E:/news4.txt");
        fileWriter.flush();
        fileWriter.close();//close == flush+关闭
    }
    //字符数组写
    public void test2() throws IOException {
        FileWriter fileWriter = new FileWriter("E:/news4.txt",true);
        String str = "打扫宿舍!2!3asdf";
        char[] chars = str.toCharArray();
        fileWriter.write(chars);
        System.out.println("打扫宿舍!2!3asdf=====>>>已写入到E:/news4.txt");
        fileWriter.flush();
        fileWriter.close();//close == flush+关闭
    }
}

2. BufferedWriter缓冲字符输入流

处理流,输出内容到news4.txt中:

在这里插入图片描述

import java.io.*;

/**
 * 字符缓冲输出流
 */
public class BufferedWriterTest {
    public static void main(String[] args) {
        BufferedWriterTest bufferedWriterTest = new BufferedWriterTest();
        try {
            bufferedWriterTest.test();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void test() throws IOException {
        System.out.println("===>>>>write(chars),将字符串:BufferedWriter缓冲字符输出流 输到E:/news4.txt<<<====");
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("E:/news4.txt"));
        String data = "BufferedWriter缓冲字符输入流";
        char[] chars = data.toCharArray();
        bufferedWriter.write(chars);
        bufferedWriter.close();

        System.out.println("===>>>>write(chars),将news1.txt文件中内容,输出到E:/news4.txt,newLine()方法换行<<<====");
        BufferedReader bufferedReader = new BufferedReader(new FileReader("E:/news1.txt"));
        BufferedWriter bufferedWriter2 = new BufferedWriter(new FileWriter("E:/news4.txt",true));
        bufferedWriter2.newLine();//流中自己输出换行
        int charCount = 0;
        char[] chars1 = new char[5];
        while ((charCount=bufferedReader.read(chars1))!=-1){
            bufferedWriter2.write(chars1,0,charCount);
        }
        bufferedWriter2.close();
    }

}

六、对象流

idea实现序列化,UID的快捷键

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

序列化需要遵守的规则
  1. 系列化和反序列化顺序一直
  2. 序列化对象要实现Serializable接口,并最好添加SerialVersionUID,提高版本兼容性
  3. 序列化对象时,不会序列化用static和transient修饰的成员,static是类的东西,我们序列化的是实例对象,所以不实例化static,transient是专门标识字段不能序列化的关键字
  4. 序列化对象,里面的属性类型也需要实现序列化接口
  5. 序列化拥有可继承性,父类实现Serializable接口,子类都会默认实现

1. ObjectInputStream对象字节输入流

将Student对象序列化到student.dat文件:basics_of_java_io/io_stream/objectStream/SerializableTest.java
  1. 新建Student实体类(记住重写toString())
    在这里插入图片描述
  2. 编写序列化代码
    在这里插入图片描述
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class SerializableTest {
    public static void main(String[] args) {
        SerializableTest serializableTest = new SerializableTest();
        try {
            serializableTest.testObjectOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 将Student对象序列化到student.dat文件
     * @throws IOException
     */
    public void testObjectOutputStream()throws IOException {
        Student student = new Student();
        student.setUsername("张三");
        student.setAge(15);
        String filePath = "E:/Student.dat";//序列化到指定位置文件
        //需要序列化到指定文件,需要传入节点流,否则不需要
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));

        //因为基本数据类型包装类都实现了Serializable接口,所以都可以直接序列化
        oos.writeInt(10);
        oos.writeBoolean(true);
        oos.writeChar('a');
        oos.writeUTF("字符串");
        //序列化Student对象
        oos.writeObject(student);

        oos.close();
        System.out.println("序列化完成!!!!!!!!!!!!!!!!!!!!!!");


    }
}

2. ObjectOutputStream对象字节输出流

将student.bat文件,反序列化成java对象:basics_of_java_io/io_stream/objectStream/SerializableTest.java

在这里插入图片描述

    /**
     * 将student.bat文件,反序列化成java对象
     * @throws IOException
     */
    public void testObjectInputStream() throws IOException{
        String filePath = "E:/Student.dat";//反序列化所需文件路径
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
        //读取顺序和保存顺序必须一致
        int read = ois.readInt();
        boolean b = ois.readBoolean();
        char c = ois.readChar();
        String s = ois.readUTF();
        Student student = null;
        try {
            student = (Student)ois.readObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        ois.close();
        System.out.println("反序列化完毕:==>>"+read+"==>>"+b+"==>>"+c+"==>>"+s+"==>>"+student+"==>>");
    }
如果你将toString方法删除(或者随便改点类结构,非变量),只要加了ID依然可以反序列成功
  1. 因为ID是我们写死的,但是如果不规定ID,它会根据类结构随机生成,所以我们反序列化的时候,因为去掉了toString方法,导致ID不一致,无法反序列化成功
  2. 以下是,不指定UID的情况,我们删除了toString,导致随机生成ID不一致,报错
    在这里插入图片描述
  3. 所以我们只要实现Serializable接口,就尽量生成一个UID

七、标准输入输出流

类型默认设备
System.inInputStream键盘
System.outPrintStream显示器

public class ImputAndOutput {
    public static void main(String[] args) {
        //System.in 是 System 类的  public final static InputStream in = null; 属性
        //System.in 编译类型 InputStream
        //System.in 运行类型为 java.io.BufferedInputStream
        //System.in 标准输入,代表键盘
        //new Scanner(System.in); 就是接收"键盘"输入,所以他是用IO流实现的,需要关掉。scanner.close();
        System.out.println("System.in 运行类型为 :"+System.in.getClass());//标准输入
        //System.out 是 System 类的 public final static PrintStream out = null; 属性
        //System.out 编译类型 PrintStream
        //System.out 运行类型为 java.io.PrintStream
        //System.out 标准输出,代表显示器
        //System.out.println("hello"); 就是输出字符串打印到显示器
        System.out.println("System.out 运行类型为 :"+System.out.getClass());//标准输出
    }
}

八、转换流

将字节流转换为字符流
  1. 常用于解决乱码问题
  2. 处理纯文本数据时,字符流效率更高,可以有效解决中文乱码,建议将字节流转换成字符流
  3. 可以指定编码格式,for example(例如):utf-8、gbk、gb2312、ISO8859-1等等

1. InputStreamReader字节输入转换流

Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)
通过转换流,使用utf-8编码读取news3.txt文件:basics_of_java_io/io_stream/transformation/InputStreamReaderTest.java

在这里插入图片描述

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

/**
 * 转换流,InputStreamReader
 */
public class InputStreamReaderTest {
    public static void main(String[] args) {
        InputStreamReaderTest inputStreamReaderTest = new InputStreamReaderTest();
        try {
            inputStreamReaderTest.test1();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void test1() throws IOException{
        //转换流
        InputStreamReader isr = new InputStreamReader(new FileInputStream("E:/news3.txt"),"UTF-8");
        //使用缓冲流,提高效率
        BufferedReader br = new BufferedReader(isr);
        //读取
        int dataCount = 0;
        char[] chars = new char[10];
        while((dataCount = br.read(chars))!=-1){
            System.out.print(new String(chars,0,dataCount));
        }
        br.close();//关闭外层流,会自动关闭里层流
        //isr.close();
    }
}

2. OutputStreamWriter字节输出转换流

Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)
通过转换流,使用utf-8编码读取news3.txt文件,然后用utf-8编码写入news4.txt:basics_of_java_io/io_stream/transformation/OutputStreamWriterTest.java

在这里插入图片描述

import java.io.*;

/**
 * 转换流,OutputStreamWriter
 */
public class OutputStreamWriterTest {
    public static void main(String[] args) {
        OutputStreamWriterTest outputStreamWriterTest = new OutputStreamWriterTest();
        try {
            outputStreamWriterTest.test1();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void test1()throws IOException {
        //转换流
        InputStreamReader isr = new InputStreamReader(new FileInputStream("E:/news3.txt"),"UTF-8");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:/news4.txt"), "utf-8");
        //使用缓冲流,提高效率
        BufferedWriter bw = new BufferedWriter(osw);
        BufferedReader br = new BufferedReader(isr);
        //写入
        int dataCount = 0;
        char[] chars = new char[10];
        while((dataCount = br.read(chars))!=-1){
            System.out.print(new String(chars,0,dataCount));
            bw.write(chars,0,dataCount);
        }
        br.close();//关闭外层流,会自动关闭里层流
        bw.close();
        System.out.println("用utf-8编码写入完成");
    }
}

九、打印流

专门用来打印的流(到控制台或文件中),只有输出流,没由输入流。可以用来做自己的日志系统

1. PrintStream字节打印流

将System.out.println("");语句的打印位置换成new5.txt文件,不是控制台:basics_of_java_io/io_stream/print/PrintStreamTest.java

在这里插入图片描述

import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;

/**
 * 字节打印流
 */
public class PrintStreamTest {
    public static void main(String[] args) {
        PrintStreamTest printStreamTest = new PrintStreamTest();
        try {
            printStreamTest.test1();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void test1() throws IOException{
        //字节打印流
        PrintStream out = System.out;
        //输出信息到控制台
        out.println("通过PrintStream输出信息到控制台");
        out.write("println底层调用write完成功能,所以调用write()效果一样".getBytes(StandardCharsets.UTF_8));
        //修改打印流,打印位置,为new5.txt文件
        System.setOut(new PrintStream("E:/new5.txt"));
        System.out.println("System.setOut(new PrintStream(\"E:/new5.txt\"));将打印位置设置为new5.txt");
        out.flush();
        out.close();
    }
}

2. PrintWriter字符打印流

打印字符效率更高,依然可以使用它打印到控制台,或者文件:basics_of_java_io/io_stream/print/PrintWriterTest.java

在这里插入图片描述

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

/**
 * 字符打印流
 */
public class PrintWriterTest {
    public static void main(String[] args) {
        PrintWriterTest printWriterTest = new PrintWriterTest();
        try {
            printWriterTest.test1();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void test1()throws IOException{
        //打印到控制台
        PrintWriter systemOut = new PrintWriter(System.out);
        systemOut.print("指定输出流为标准输出流System.out,输出");
        //打印到文件
        PrintWriter pw = new PrintWriter(new FileWriter("E:/new5.txt", true));
        pw.println("指定输出流为文件输出流new FileWriter,输出");
        systemOut.close();
        pw.close();
    }
}

十、实践

1. 有一个mysql.properties配置文件,读取其中配置

有一个mysql.properties,读取其中配置

在这里插入图片描述

1. 传统方法,通过字符输入流,扩展性不好

在这里插入图片描述

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

/**
 * 读取mysql.properties文件配置信息
 */
public class ReadProperties {
    public static void main(String[] args) {
        ReadProperties readProperties = new ReadProperties();
        try {
            readProperties.readTradtion();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 传统方法
     * @throws IOException
     */
    public void readTradtion()throws IOException {
        InputStream is = ReadProperties.class.getClassLoader().getResourceAsStream("mysql.properties");
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String line = "";
        while((line = br.readLine())!=null){
            String[] split = line.split("=");
            System.out.println(split[0]+"========================>>>>>>"+split[1]);
        }

        br.close();
    }
}
2. Properties类
  1. 专门用于读写配置文件的集合类(配置文件格式:键=值)
  2. 键值对不需要有空格,值不需要用引号,默认String类型
    在这里插入图片描述
    /**
     * Properties类
     * @throws IOException
     */
    public void readProperties()throws IOException {
        URL resource = ReadProperties.class.getClassLoader().getResource("mysql.properties");
        FileReader fileReader = new FileReader(resource.getFile());

        Properties properties = new Properties();
        //加载配置文件
        properties.load(fileReader);
        //读取ip的值
        String ip = properties.getProperty("ip");
        System.out.println("通过Properties类读取ip==================>>>>"+ip);

        fileReader.close();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ydenergy_殷志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值