首页 > 编程语言 >13.Java的IO流

13.Java的IO流

时间:2024-10-29 23:09:20浏览次数:6  
标签:13 java String System IO new Java public out

文件

概念

  • 文件:保存数据的地方。
  • 文件流:文件在程序中是以流的形式来操作的。
  • 流:数据在数据源(文件)和程序(内存)之间经历的路径。
    • 输入流:数据从数据源(文件)到程序(内存)的路径。
    • 输出流:数据从程序(内存)到数据源(文件)的路径。

文件和文件流

常用操作

文件类

构造方法

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

获取文件信息

import java.io.File;

//获取文件信息
public class FileDemo {
    public static void main(String[] args) {
        File file = new File("E:/java学习/textFile/1.txt");
        System.out.println("文件名字:" + file.getName()); //1.txt
        System.out.println("绝对路径:" + file.getAbsoluteFile()); //E:\java学习\textFile\1.txt
        System.out.println("文件父级目录:" + file.getParent()); //E:\java学习\textFile
        System.out.println("文件大小(字节数):" + file.length()); //9
        System.out.println("文件是否存在:" + file.exists()); //true
        System.out.println("文件是否是一个文件:" + file.isFile()); //true
        System.out.println("文件是否是一个目录:" + file.isDirectory()); //false
    }
}

查看文件的编码方式:

查看文件编码方式

不同编码方式中英文所占的字节数:

编码方式 英文 中文
GB2312 1 2
GBK 1 2
GB18030 1 2
ISO-8859-1 1 1
UTF-8 1 3
UTF-16 4 4

目录操作

  • mkdir:创建一级目录
  • mkdirs:创建多级目录
  • delete:删除文件或空目录
import java.io.File;

//文件目录操作
public class FileDemo {
    public static void main(String[] args) {
        //判断文件是否存在,存在就删除,否则提示不存在
        String filePath = "E:/java学习/textFile/1.txt";
        File file = new File(filePath);
        if (file.exists()) {
            if (file.delete()) {
                System.out.println("文件删除成功!");
            } else {
                System.out.println("文件删除失败!");
            }
        } else {
            System.out.println("该文件不存在!");
        }

        //判断目录是否存在,存在就删除,否则提示不存在
        String filePath1 = "E:/java学习/textFile/folder1";
        File file1 = new File(filePath1);
        if (file1.exists()) {
            if (file1.delete()) {
                System.out.println("目录删除成功!");
            } else {
                System.out.println("目录删除失败!");
            }
        } else {
            System.out.println("该目录不存在!");
        }

        //判断多级目录是否存在,否则创建多级目录
        String filePath2 = "E:/java学习/textFile/folder1/folder1.1/folder1.1.1";
        File file2 = new File(filePath2);
        if (file2.exists()) {
            System.out.println("该多级目录存在!");
        } else {
            if (file2.mkdirs()) {
                System.out.println("创建多级目录成功!");
            } else {
                System.out.println("创建多级目录失败!");
            }
        }
    }
}

IO流原理及流的分类

IO流原理

  1. I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等。
  2. Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行。
  3. java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据。
  4. 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  5. 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

IO流原理

流的分类

  • 按操作数据单位不同分为:字节流(8 bit))适合操作二进制文件(声音,word),字符流(按字符) 文本文件,其中不同文件编码类型字符所占字节个数不同。
  • 按数据流的流向不同分为:输入流,输出流。
  • 按流的角色的不同分为:节点流,处理流/包装流。
(抽象基类) 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

注意:

  1. Java的I0流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的。
  2. 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。

常用的类

JavaIO流体系图

JavaIO流体系图

字节流

  • InputStream抽象类是所有类字节输入流的超类。
  • 常用子类
    • FileInputStream 文件输入流
    • BufferedInputStream 缓冲字节输入流
    • ObjectInputStream 对象字节输入流

字节输入流类

FileInputStream

常用方法

FileInputStream常用方法

代码示例:read()方法

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

//FileInputStream read()方法
public class FileInputStreamDemo {
    public static void main(String[] args) {
        //read()方法 一次从输入流中读取一个字节的数据 单字节读取
        File file = new File("E:/java学习/textFile/1.txt");
        FileInputStream fileInputStream = null;
        try {
            //创建FileInputStream对象
            fileInputStream = new FileInputStream(file);
            //read:从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。
            //数据的下一个字节,如果达到文件的末尾,返回-1。读一个字节,如果中文,有可能不止一个字节,会乱码。
            int read = -1;
            while ((read = fileInputStream.read()) != -1) {
                System.out.println((char) read); //转成char显示
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

代码示例:read(byte[] b)方法

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

//FileInputStream read(byte[] b)方法
public class FileInputStreamDemo {
    public static void main(String[] args) {
        //读文件
        String filePath = "E:/java学习/textFile/1.txt";
        FileInputStream fileInputStream = null;
        try {
            //创建FileInputStream对象
            fileInputStream = new FileInputStream(filePath);
            //read(byte[] b):从该输入流读取最多b.length字节的数据到字节数组。此方法将阻塞,直到某些输入可用。
            //返回值: 读入缓冲区的总字节数,如果没有更多的数据,因为文件的结尾已经到达,返回-1 。
            //乱码可能:缓冲区边界的一个中文字符拆成了多个字节
            //字节数组
            byte[] buffer = new byte[8]; //一次读8个字节
            int readLen = 0; //一次读取的字节长度
            while ((readLen = fileInputStream.read(buffer)) != -1) {
                System.out.println(readLen);
                System.out.println(new String(buffer, 0, readLen)); //显示
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

FileOutputStream

字节输出流类

常用方法

FileOutputStream常用方法

代码示例

import java.io.*;

/**
 * 演示使用FileOutputStream将数据写到文件中,
 * 如果该文件不存在,则创建该文件
 */
public class FileOutputStreamDemo {
    public static void main(String[] args) {
        File file = new File("E:/java学习/textFile/1.txt");
        FileOutputStream fileOutputStream = null;
        try {
            //创建FileOutputStream 对象
            //new FileOutputStream(file); 覆盖写
            //new FileOutputStream(file,true); 构造器后面的一个参数append设置为true,不覆盖原来的数据,追加写
            fileOutputStream = new FileOutputStream(file, true);

            //写入一个字节
            fileOutputStream.write('a'); //char自动转换int

            //写入字符串
            String str = "QWER";
            //str.getBytes()可以把字符串转换为字节数组
            fileOutputStream.write(str.getBytes());

            //write(byte[] b, int off, int len)
            //将len字节从位于偏移量off的指定字节数组写入此文件输出流
            fileOutputStream.write(str.getBytes(), 1, str.length() - 1);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

作业

完成英语文件的拷贝

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

//完成英语文件的拷贝
public class FileDemo {
    public static void main(String[] args) {
        String inputPath = "E:/java学习/textFile/1.txt";
        FileInputStream fileInputStream = null;
        String outputPath = "E:/java学习/textFile/2.txt";
        FileOutputStream fileOutputStream = null;
        try {
            int readLen = 0;
            byte[] buffer = new byte[256];
            fileInputStream = new FileInputStream(inputPath);
            fileOutputStream = new FileOutputStream(outputPath);
            while ((readLen = fileInputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, readLen);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

字符流

FileReader和FileWriter是字符流,即按照字符来操作io。

FileReader

下方为FileReader的继承关系类图,继承InputStreamReader。

FileReader的继承关系类图

相关方法

方法 说明
new FileReader(File/String) 构造方法
read() 每次读取单个字符(一个汉字算一个字符),返回该字符,如果到文件末尾返回-1
read(char[]) 批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1

字符数组转换为字符串处理的相关API:

new String(char[]) : 将char[]转换成String

new String(char[], off, len):将char[]的指定部分转换成String

代码示例:使用read()读取文件

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

//FileReader read()方法
public class FileReaderDemo {
    public static void main(String[] args) {
        //read()方法 一次从输入流中读取一个字符的数据 单字符读取
        String filePath = "E:/java学习/textFile/1.txt";
        FileReader fileReader = null;
        try {
            //创建FileReader对象
            fileReader = new FileReader(filePath);
            //read() 每次读取单个字符(一个汉字算一个字符),返回该字符,如果到文件末尾返回-1。
            int read = 0;
            while ((read = fileReader.read()) != -1) {
                System.out.print((char) read);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

代码示例:使用read(char [])读取

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

//FileReader read(char [])方法
public class FileReaderDemo {
    public static void main(String[] args) {
        String filePath = "E:/java学习/textFile/1.txt";
        FileReader fileReader = null;
        try {
            //创建FileReader对象
            fileReader = new FileReader(filePath);
            //read(char []) 批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1。
            int readLen = 0;
            char[] buffer = new char[256];
            while ((readLen = fileReader.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, readLen));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

FileWriter

下方为FileWriter的继承关系类图,继承OutputStreamWriter。

FileWriter的继承关系类图

常用方法

方法 说明
new FileWriter(File/String) 构造方法,覆盖模式,相当于流的指针在首端
new FileWriter(Fiie/String , true) 构造方法,追加模式,相当于流的指针在尾端
write(int) 写入单个字符
write(char[]) 写入指定数组
write(char[],off,len) 写入指定数组的指定部分
write (string) 写入整个字符串
write(string,off, len) 写入字符串的指定部分

字符串转换为字符数组处理的相关API:

String类的toCharArray:将String转换为char[]

⭐️注意:
FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!

代码示例

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

//FileWriter
public class FileWriterDemo {
    public static void main(String[] args) {
        String filePath = "E:/java学习/textFile/1.txt";
        FileWriter fileWriter = null;
        try {
            //创建FileWriter 对象
            //new FileWriter(file); 覆盖写
            //new FileWriter(file,true); 构造器后面的一个参数append设置为true,不覆盖原来的数据,追加写
            fileWriter = new FileWriter(filePath, true);

            //1.write() 写入单个字符
            fileWriter.write("H");

            //2.write(char []) 写入指定数组
            char[] chars = {'J', '林', '1'};
            fileWriter.write(chars);

            //3.write(char [], off, len) 写入指定数组的指定部分
            fileWriter.write("林黛玉".toCharArray(), 0, 2);

            //4.write(string) 写入整个字符串
            fileWriter.write("孙悟空");

            //5.write(string, off, len) 写入字符串的指定部分
            fileWriter.write("刘玄德", 0, 2);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //对于FileWriter,一定要关闭流,只有在close或者flush之后才能真正地把数据写入到文件中
                if (fileWriter != null) {
                    fileWriter.close(); //等价于flush()+关闭流
                    //fileWriter.flush();
                    /*
                    两个方法源码最终调用了OutputStream的writeBytes方法
                    private void writeBytes() throws IOException {
                        bb.flip();
                        int lim = bb.limit();
                        int pos = bb.position();
                        assert (pos <= lim);
                        int rem = (pos <= lim ? lim - pos : 0);

                            if (rem > 0) {
                        if (ch != null) {
                            if (ch.write(bb) != rem)
                                assert false : rem;
                        } else {
                            out.write(bb.array(), bb.arrayOffset() + pos, rem);
                        }
                        }
                        bb.clear();
                        }
                     */
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

节点流和处理流

基本介绍

  • 节点流可以从一个特定的数据源读写数据,如FileReader、 FileWriter。

    节点流

  • 处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader、BufferedWriter。

    处理流

  • 节点流和处理流一览图

    节点流和处理流

辅助理解处理流(包装流):以BufferedReader为例

BufferedReader类中,有属性Reader,即可以封装一个节点流,该节点流可以是任意的,只要是Reader子类。(装饰者模式)

BufferedReader

区别和联系

  1. 节点流是底层流/低级流,直接跟数据源相接。
  2. 处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
  3. 处理流(包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]。

模拟代码(模拟修饰器设计模式)

//模拟修饰器设计模式
public class DecoratorDemo {
    public static void main(String[] args) {
        BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());
        bufferedReader_.readFile();
        bufferedReader_.readFiles(2);

        //通过bufferReader_多次读取字符串
        BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_());
        bufferedReader_1.readString();
        bufferedReader_1.readStrings(2);

        /*
        输出结果:
        对文件进行读取...
        对文件进行读取...
        对文件进行读取...
        读取字符串...
        读取字符串...
        读取字符串...
        */
    }
}

abstract class Reader_ {
    public void readFile() {

    }
    public void readString() {

    }
    //也可以将readFile和readString写成一个抽象方法,利用动态绑定机制
}

//模拟节点流
class FileReader_ extends Reader_ {
    public void readFile() {
        System.out.println("对文件进行读取...");
    }
}

//模拟字符流
class StringReader_ extends Reader_ {
    public void readString() {
        System.out.println("读取字符串...");
    }
}

//模拟处理流(包装流)
class BufferedReader_ extends Reader_ {
    private Reader_ reader_;

    public BufferedReader_(Reader_ reader_) {
        this.reader_ = reader_;
    }

    public void readFile() { //封装一层
        reader_.readFile();
    }

    public void readString() { //封装一层
        reader_.readString();
    }

    //让方法更加灵活,多次读取文件,或者加缓冲char[]...
    public void readFiles(int num) {
        for (int i = 0; i < num; i++) {
            reader_.readFile();
        }
    }

    //扩展readString,批量处理字符串数据
    public void readStrings(int num) {
        for (int i = 0; i < num; i++) {
            reader_.readString();
        }
    }
}

根据示例代码也不难理解处理流(包装流)的两个主要方面的功能:

  • 性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
  • 操作的便捷:处理流(包装流)可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便。

处理流讲解

  • BufferedReader和BufferedWriter属于字符流,是按照字符来读取数据的。
  • BufferedInputStream和BufferedInputStream是字节流,是按照字节来读取数据的。
  • 关闭处理流时,只需要关闭外层流即可,关闭处理流包含关闭节点流。

处理流:BufferedReader和BufferedWriter

代码示例一:读取文本文件

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

//BufferedReader 读取文本文件
public class BufferedReaderDemo {
    public static void main(String[] args) {
        String filePath = "E:/java学习/textFile/1.txt";
        BufferedReader bufferedReader = null;
        try {
            //创建BufferedReader对象
            bufferedReader = new BufferedReader(new FileReader(filePath));
            //读取
            /*
            说明:
            1.bufferedReader.readLine(); //按行读取
            2.当返回null时,表示文件读取完毕。
            */
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.print(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    //关闭流 只需要关闭处理流(包装流),底层自动关闭节点流
                    bufferedReader.close();
                    /*
                    源码:
                    private Reader in;

                    public void close() throws IOException {
                        synchronized (lock) {
                            if (in == null)
                                return;
                            try {
                                in.close();
                            } finally {
                                in = null;
                                cb = null;
                            }
                        }
                    }
                     */
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

代码示例二:写文本文件

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

//BufferedWriter 写文本文件
public class BufferedWriterDemo01 {
    public static void main(String[] args) {
        String filePath = "E:/java学习/textFile/1.txt";
        BufferedWriter bufferedWriter = null;
        try {
            //创建BufferedWriter对象
            //说明 new FileWriter(filePath,true)  追加写
            //说明 new FileWriter(filePath)  覆盖写
            bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));
            bufferedWriter.write("Hello World1");
            bufferedWriter.newLine(); //插入一个和系统相关的换行
            bufferedWriter.write("Hello World2");
            bufferedWriter.write("Hello World3");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedWriter != null) {
                    //关闭外层流会自动关闭内部流
                    bufferedWriter.close();
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

代码示例三:复制文本文件

import java.io.*;

//BufferedReader和BufferedWriter 复制文本文件
public class BufferedDemo {
    public static void main(String[] args) {
        //BufferedReader和BufferedWriter是按照字符操作的
        //不要去操作二进制文件,可能造成文件损坏
        String srcFilePath = "E:/java学习/textFile/1.txt";
        String destFilePath = "E:/java学习/textFile/2.txt";
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        try {
            bufferedReader = new BufferedReader(new FileReader(srcFilePath));
            bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                bufferedWriter.write(line);
                bufferedWriter.newLine();
                //bufferedWriter.write(line + "\n"); //等同于上边两行代码
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    //关闭外层流会自动关闭内部流
                    bufferedReader.close();
                }
                if (bufferedWriter != null) {
                    //关闭外层流会自动关闭内部流
                    bufferedWriter.close();
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        }

    }
}

处理流:BufferedInputStream和BufferedOutputStream

  • BufferedlnputStream是字节流,在创建BufferedlnputStream时,会创建一个内部缓冲区数组。

    BufferedInputStream

  • BufferedOutputStream是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统。

    BufferedOutputStream

代码示例:完成二进制文件的拷贝

import java.io.*;

//BufferedInputStream和BufferedOutputStream 完成二进制文件的拷贝
public class BufferedDemo02 {
    public static void main(String[] args) {
        String srcFilePath = "E:/java学习/textFile/1.wav";
        String destFilePath = "E:/java学习/textFile/2.wav";
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        byte[] buffer = new byte[1024];
        int len = 0;
        try {
            bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFilePath));
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFilePath));
            while ((len = bufferedInputStream.read(buffer)) != -1) {
                bufferedOutputStream.write(buffer, 0, len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedInputStream != null) {
                    //关闭外层流会自动关闭内部流
                    bufferedInputStream.close();
                }
                if (bufferedOutputStream != null) {
                    //关闭外层流会自动关闭内部流
                    bufferedOutputStream.close();
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

对象处理流:ObjectInputStream和ObjectOutputStream

看一个需求:(保存数据的值和相应的数据类型)

  1. 将int num = 100这个int数据保存到文件中,注意不是100数字,而是int 100,并且,能够从文件中直接恢复int 100。
  2. 将Dog dog = new Dog(“小黄”,3)这个dog对象保存到文件中,并且能够从文件中恢复。
  3. 上面的要求,就是能够将基本数据类型或者对象进行序列化和反序列化操作。

序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的值数据类型

  2. 反序列化就是在恢复数据时,恢复数据的值数据类型

  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:

    Serializable //这是一个标记接口,没有方法

    Externalizable //该接口有方法需要实现,一般使用上面的方法

基本介绍

  1. 功能:提供了对基本类型或对象类型的序列化和反序列化的方法。
  2. ObjectOutputStream提供序列化功能。
  3. ObjectlnputStream提供反序列化功能。

ObjectOutputStream

ObjectOutputStream

代码示例一

题目描述:使用ObjectOutputStream序列化基本数据类型和一个Dog对象(name, age),并保存到data.dat文件中。

import java.io.*;

//ObjectOutputStream 序列化
public class ObjectOutputStreamDemo {
    public static void main(String[] args) {
        //题目描述:使用ObjectOutputStream序列化基本数据类型和一个Dog对象(name, age),并保存到data.dat文件中。
        //序列化后,保存的文件的格式,不是纯文本,而是按照它的格式来保存
        String filePath = "E:/java学习/textFile/data.dat";
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));

            //序列化数据到data.dat文件中
            objectOutputStream.writeInt(100); //自动装箱:int->Integer(实现了Serializable)
            objectOutputStream.writeBoolean(true); //自动装箱:boolean->Boolean(实现了Serializable)
            objectOutputStream.writeChar('a'); //char
            objectOutputStream.writeDouble(3.14); //double
            objectOutputStream.writeFloat(3.14f); //float
            objectOutputStream.writeUTF("Hello,World"); //String

            //保存一个dog类
            //如果需要实现序列化某个类的对象,Serializable
            objectOutputStream.writeObject(new Dog("旺财", 3));

            System.out.println("序列化完成");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (objectOutputStream != null) {
                    //关闭外层流会自动关闭内部流
                    objectOutputStream.close();
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

class Dog implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

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

代码示例二

题目描述:使用ObjectInputStream读取data.dat文件并反序列化恢复数据。

import java.io.*;

//ObjectInputStream 反序列化
public class ObjectInputStreamDemo {
    public static void main(String[] args) {
        //题目描述:使用ObjectInputStream读取data.dat文件并反序列化恢复数据。
        //指定反序列化文件
        String filePath = "E:/java学习/textFile/data.dat";
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(new FileInputStream(filePath));

            //读取(反序列化)的顺序需要和你保存的数据(序列化)的顺序一致, 否则会出现异常
            System.out.println(objectInputStream.readInt());
            System.out.println(objectInputStream.readBoolean());
            System.out.println(objectInputStream.readChar());
            System.out.println(objectInputStream.readDouble());
            System.out.println(objectInputStream.readFloat());
            System.out.println(objectInputStream.readUTF());

            //dog的编译类型是Object,运行类型是Dog
            Object dog = objectInputStream.readObject();
            System.out.println(dog.getClass()); //运行类型会自动转换,底层Object->Dog
            System.out.println(dog);

            //访问Dog类的方法
            //1.向下转型
            //2.Dog类放在可以引用的地方,且与序列化的位置、定义都要一致
            Dog dog1 = (Dog) dog;
            System.out.println(dog1.getName());
            //注意:如果在序列化后,类的定义被修改了,例如增加了方法,会导致反序列化失败,可以添加SerialVersionUID解决这个问题
            //注意:在序列化时,包名信息已经固定,所以不能反序列化为不同包的Dog对象
            
            System.out.println("反序列化完成");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (objectInputStream != null) {
                    //关闭外层流会自动关闭内部流
                    objectInputStream.close();
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

注意事项和细节说明

  1. 读写顺序要一致。
  2. 要求实现序列化或反序列化的对象,需要实现Serializable接口。
  3. 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性。
  4. 序列化对象时,默认将里面所有属性都进行序列化,除了static或transient修饰的成员。
  5. 序列化对象时,要求里面属性的类型也需要实现序列化接口。
  6. 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化。

输入流和输出流

标准输入输出流

类型(编译类型) 默认设备
System.in 标准输入 lnputStream 键盘
System.out 标准输出 PrintStream 显示器

代码示例

import java.util.Scanner;

//标准输入输出流
public class InOutDemo {
    public static void main(String[] args) {
        //System类中: public final static InputStream in = null;
        //System.in 编译类型 InputStream
        //System.in 运行类型 BufferedInputStream
        //表示的是标准输入:键盘
        System.out.println(System.in.getClass()); //class java.io.BufferedInputStream

        //System类中::public final static PrintStream out = null;
        //System.out 编译类型 PrintStream
        //System.out 运行类型 PrintStream
        //标准输出 显示器
        System.out.println(System.out.getClass()); //class java.io.PrintStream

        System.out.println("Hello World"); //使用out对象将数据输出到显示器上
        Scanner scanner = new Scanner(System.in); //使用标准输入 键盘接收数据
        System.out.println("输入内容");
        String next = scanner.next();
        System.out.println("next=" + next);
        scanner.close();
    }
}

转换流(InputStreamReader和OutputStreamWriter)

问题引入

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

public class BufferedReaderDemo {
    public static void main(String[] args) {
        //读取txt文件
        //1.创建字符输入流 BufferedReader[处理流]
        //2.使用BufferedReader对象读取1.txt
        //3.默认情况下,读取文件是按照utf-8编码的。若文件不是utf-8则读取文件可能会出现文件乱码问题。
        //介绍一下ANSI国标码,ANSI并不是某一种特定的字符编码,它指的是在不同国家和地区基于ASCII扩展的编码方式。
        //和操作系统和区域设置有关,美国的系统中ANSI编码其实是ASCII编码(ASCII编码不能表示汉字,所以汉字为乱码),而中国的系统中(“汉字”正常显示)ANSI编码其实是GBK编码。
        String filePath = "E:/java学习/textFile/1.txt";
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new FileReader(filePath));
            String line = bufferedReader.readLine();
            System.out.println("读取到的内容:" + line); //文本文件为ANSI编码,而使用utf-8编码读取文件,中文乱码
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

说明

  • InputStreamReader:Reader的子类,可以将InputStream(字节流)包装(转换)成Reader(字符流)。
  • OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)。
  • 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流。
  • 可以在使用时指定编码格式(比如utf-8,gbk,gb2312,ISO8859-1等)。

类图

InputStreamReader

代码示例一

使用InputStreamReader转换流解决中文乱码问题,将字节流FileInputStream 包装成(转换成)字符流InputStreamReader,对文件进行读取(按照utf-8/gbk格式),进而再包装成BufferedReader。

import java.io.*;

//InputStreamReader
public class InputStreamReaderDemo {
    public static void main(String[] args) {
        String filePath = "E:/java学习/textFile/1.txt";
        //1. 把FileInputStream转成InputStreamReader
        //2.指定编码:gbk
        //InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "gbk");
        //3.把InputStreamReader传入BufferedReader
        //BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        BufferedReader bufferedReader = null;
        try {
            //把2,3合并到一起
            bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"gbk"));
            //4.读取
            String line = bufferedReader.readLine();
            System.out.println("读取到的内容:" + line); //文本文件为ANSI编码,而使用utf-8编码读取文件,中文乱码
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    //5.关闭外层流
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

代码示例二

编程将字节流FileOutputStream包装成(转换成)字符流OutputStreamWriter,对文件进行写入(按照gbk格式,可以指定其他,比如:utf-8)。

import java.io.*;

//OutputStreamWriter
public class OutputStreamWriterDemo {
    public static void main(String[] args) {
        String filePath = "E:/java学习/textFile/1.txt";
        OutputStreamWriter outputStreamWriter = null;
        try {
            outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath, true), "gbk");
            outputStreamWriter.write("Bye");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStreamWriter != null) {
                    //关闭外层流
                    outputStreamWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

打印流(PrintStream和PrintWriter)

  • 打印流只有输出流,没有输入流。

类图

PrintStream

PrintWriter

代码示例一

import java.io.IOException;
import java.io.PrintStream;

//PrintStream
public class PrintStreamDemo {
    public static void main(String[] args) {
        PrintStream out = System.out;
        //在默认情况下,PrintStream输出数据的位置是 标准输出,即显示器
        /*
            public void print(String s) {
                if (s == null) {
                    s = "null";
                }
                write(s);
            }
         */
        try {
            out.print("Hello World");
            //因为print底层使用的是write,所以我们可以直接调用write进行打印/输出
            out.write("Hello World".getBytes());

            //我们可以修改打印流的输出位置/设备
            /*
                默认打印/输出的位置是显示器,那么也可以修改输出的位置
                比如:修改输出位置改到E:/java学习/textFile/1.txt
                public static void setOut(PrintStream out) {
                    checkIO();
                    setOut0(out); //native方法, 修改了out位置
                }
             */
            System.setOut(new PrintStream("E:/java学习/textFile/1.txt"));
            System.out.println("Kobe");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();
            }
        }

    }
}

代码示例二

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

//PrinterWriter
public class PrintWriterDemo {
    public static void main(String[] args) {
        PrintWriter printerWriter = new PrintWriter(System.out);
        printerWriter.print("Hello World");
        printerWriter.close();

        try {
            PrintWriter printerWriter2 = new PrintWriter(new FileWriter("E:/java学习/textFile/1.txt"));
            printerWriter2.print("Hello 北京");
            printerWriter2.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Properties类

说明

  • 专门用于读写配置文件的集合类。
    配置文件的格式:
    键=值
    键=值

  • 注意:键值对不需要有空格,值不需要用引号引起来,默认类型是String。

  • 常见方法:

    • load:加载配置文件的键值对到Properties对象。
    • list:将数据显示到指定设备。
    • getProperty(key):根据键获取值。
    • setProperty(key, value):设置键值对到Properties对象。
    • store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode码。

代码示例

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

//Properties
public class PropertiesDemo {
    public static void main(String[] args) {
        //使用Properties类读取mysql.properties文件

        try {
            //1.创建Properties对象
            Properties properties = new Properties();

            //2.加载指定配置文件
            properties.load(new FileReader("E:/java学习/textFile/mysql.properties"));

            //3.把key-value显示到控制台
            properties.list(System.out);
            /*
                输出结果:
                -- listing properties --
                age=18
                name=mlt
            */

            //4.根据key获取对应的value
            String name = properties.getProperty("name");
            String age = properties.getProperty("age");
            System.out.println("name=" + name + ", age=" + age); //name=mlt, age=18

            //使用Properties类创建配置文件,修改配置文件内容
            Properties prop = new Properties();
            //如果该文件有key,就是创建,如果没有就是修改
            /*
            Properties父类是HashTable,底层
            public synchronized V put(K key, V value) {
                // Make sure the value is not null
                if (value == null) {
                    throw new NullPointerException();
                }

                // Makes sure the key is not already in the hashtable.
                Entry<?,?> tab[] = table;
                int hash = key.hashCode();
                int index = (hash & 0x7FFFFFFF) % tab.length;
                @SuppressWarnings("unchecked")
                Entry<K,V> entry = (Entry<K,V>)tab[index];
                for(; entry != null ; entry = entry.next) {
                    if ((entry.hash == hash) && entry.key.equals(key)) {
                        V old = entry.value;
                        entry.value = value;//如果是旧key就替换
                        return old;
                    }
                }

                addEntry(hash, key, value, index);//如果是新key,就添加
                return null;
            }
             */
            properties.setProperty("name", "孙悟空");
            properties.setProperty("age", "1000");
            properties.setProperty("address", "花果山");
            properties.store(new FileWriter("E:/java学习/textFile/mysql1.properties"), null);
            properties.list(System.out);
            /*
                输出结果:
                -- listing properties --
                address=花果山
                age=1000
                name=孙悟空
            */
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
}

标签:13,java,String,System,IO,new,Java,public,out
From: https://www.cnblogs.com/spicy-hot-pot/p/18514720

相关文章

  • 第六届国际科技创新学术交流大会(IAECST 2024) 暨第四届物流系统与交通运输国际学术会
    @目录一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题一、会议详情二、重要信息大会官网:https://ais.cn/u/vEbMBz提交检索:EICompendex、IEEEXplore、Scopus三、大会介绍第六届国际科技创新学术交流大会暨第四届物流系统与交通运输国际学术会议(LSTT202......
  • 第二届计算机网络技术与电子信息工程国际学术会议(CNTEIE 2024) 2024 2nd Internationa
    @目录一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题一、会议详情二、重要信息大会官网:https://ais.cn/u/vEbMBz提交检索:EICompendex、IEEEXplore、Scopus三、大会介绍第二届计算机网络技术与电子信息工程国际学术会议(CNTEIE2024)将于2024年12月6-8日......
  • P9131 [USACO23FEB] Problem Setting P 题解
    P9131[USACO23FEB]ProblemSettingP题解注意到最终形成的困难序列是一个不断包含的子集的关系,包含是非严格单调的,考虑转化为单调的形式易于计数dp。具体地,对于一些相同的困难值\(i\),算出其内部排列数\(g(i)\),于是转化成了单调的dp形式。于是实际上计算\(dp_{i}\)表示......
  • 20222413 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    1.实验内容1.1学习总结本周的学习内容为恶意代码的概念、发展历史以及分析技术。我知晓了恶意代码的不同类型及其典型案例、攻击方式和危害。同时我了解了静态分析和动态分析所采用的技术方法。1.2实践内容(1)正确使用msf编码器,veil-evasion,自己利用shellcode编程等免杀工具或......
  • javascript-Web APLs (三)
     事件流指的是事件完整执行过程中的流动路径 说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段 简单来说:捕获阶段是从父到子冒泡阶段是从子到父 实际工作都是使用事件冒泡为主事件捕获DOM.addEventListener(事件类型,事件处......
  • 从零开始的JavaScript基础!
    目录一、JavaScript的概述二、如何在HTML页面中使用JS(一)、行内式 (二)、内嵌式(三)、外链式(四)、基本执行顺序1.从上到下线性执行:2.阻塞行为:(五)、JS输出方式1. alert() 通过浏览器弹出框进行输出 2.document.write() 直接在网页页面中进行输出 3.console.log()......
  • 2024.10.24 The 2021 ICPC Northwestern Russia Regional Contest
    比赛链接Solved:8/14Penalty:909Rank:23前五道签到题ABCHL。K.KaleidoscopicRoute题意给一张带边权的图,求一条1到n的路径,使经过的边数最少的同时边的极差最大。题解求出最短路图,然后DAG上dp:f和g分别表示从1到这个点能经过的最大边权和最小边权。然后每转移一条边(x,y,z......
  • 2024.10.4 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest
    比赛链接Solved:7/11Penalty:914Rank:1/74Rank(vp):63/1k+Dirt:22%G答案是4*纯色块数+5。考虑怎么维护这个纯色块数。这道题的修改保证了一个块纯色当且仅当其行列都纯色。因此对行列分别维护一棵线段树,维护每一层分别有多少个纯色节点,按层乘起来相加就行。K1操作的增加量......
  • 2024.10.3 2022-2023 ICPC Brazil Subregional Programming Contest
    比赛链接Solved:12/14Rank:5/1k+Rank(vp):49/2k+Penalty:1619Dirt:45%前10个题都比较简单/套路。L做法很好想。但是……因为不会写启发式合并卡了40min,警钟长鸣!intsum[N];map<int,int>col[N];intsz[N];llnow[N],ans[N];voidmrg(intx,inty){x=find(x),y=fi......
  • P9994 [Ynoi Easy Round 2024] TEST_132
    题意给定平面上\(n\)个点,保证两两横纵坐标不同:对于所有横坐标为\(x\)的点,权值\(v_i=v_i^2\)。询问所有纵坐标为\(y\)的点的权值之和。\(n\le10^6\)。Sol根号分治,考虑对于所有横坐标相同的点分组。对于修改操作,若当前修改的组大小\(\leB\),那么直接暴力修......