java-01基础篇-03 Java IO流

一,流的定义

        流(Stream)主要指定的是数据的处理方式,以及对于目标内容的处理机制,在现实生活中输入和输出属于两个不同的处理阶段。而在程序中的流指定的是数据的处理方向。

        数据的处理方式有两种,一种是数据的输入;一种的数据的输出。数据输入到某个接纳数据的终端;从某个终端将数据输送出去。如果终端是文件;java里面提供FileInputStream. FileOutputStream. 如果终端是内存,java提供了ByteArrayInputStream,ByteArrayOutputStream

       

二,字节流&字符流

数据类型的不同

        字节流,数据的输入输出方式是以字节为单位进行传输的。适用于所有场景,毕竟计算机里面的数据就是二进制的形式。案例有图像,音频,视频等。

        字符流,数据的输入输出方式是以字符串为单位进行传输的。适用于文本数据,例如文本文件,配置文件等。

        字符流提供一些方便处理字符的方法,例如readLine()可以一次读取一行文本数据,而字节流则需要通过一些额外的处理才能实现类似的功能!

字符编码处理

        字节流是以字节为单位处理数据,不会设计字符编码的转换

        字符流在读取或写入字符时,会自动处理字符编码,可以避免因为字符编码不同引起的乱码问题。

性能考虑问题

        字节流操作性能快一点,因为字符流涉及到字符编码的转换问题,可能会引入额外的性能开销。

三,字节流

3.1 文件流 FileInputStream&FileOutputStream

        java.io.InputStream 类是在IO包中提供专门实现字节数据的输入流!具体实现子类有一个文件输入流(java.io.FileInputStream)

        java.io.OutputStream 类是在IO包中提供专门实现字节数据的输出流!具体实现子类有一个文件输出流(java.io.FileOutputStream) 

        文件流,以文件作为数据存储介质,并提供数据输入输出操作。

        当需要从数据存储介质(文件)中读取数据,可以使用FileInputStream将数据读取出来;

        当需要将数据保存至数据存储介质(文件)时,可以使用FileOutputStream将数据写入进去;

因为现在的数据存储介质是文件。所以用文件流

【文件流-写案例】

package org.toast.io;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;

/**
 * @author toast
 * @time 2024/3/30
 * @remark
 */
public class TestOutputFile {

    public static void main(String[] args) {
        String path = "src/main/resources/test/demo-file.txt";
        URL resource = TestOutputFile.class.getClassLoader().getResource(path);
        String content1 = "正确认识意志力的产生,消耗以及它对我们的影响\n";
        String content2 = "学会培养成年人孩子意志力的实用方法\n";
        String content3 = "学会灵活运用意志力来改善生活甚至改变人生\n";
        try {
            FileOutputStream outputStream = new FileOutputStream(new File(path));
            /*
             * 当接纳数据终端是文件时(demo-file.txt);
             * 可以使用FileOutputStream将数据输出到指定的文件当中
             */
            outputStream.write(content1.getBytes()); // 将内容1写入 demo-file.txt文件中
            outputStream.write(content2.getBytes()); // 将内容2写入 demo-file.txt文件中
            outputStream.write(content3.getBytes()); // 将内容3写入 demo-file.txt文件中
            outputStream.close();
            System.out.println("写入完毕!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

【文件流-读写案例】

package org.toast.io;

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

/**
 * @author toast
 * @time 2024/3/30
 * @remark
 */
public class TestInputFile {
    public static void main(String[] args) {
        String source = "src/main/resources/test/source.txt";
        String target = "src/main/resources/test/target.txt";
        try (
                FileInputStream inputStream = new FileInputStream(new File(source));
                FileOutputStream outputStream = new FileOutputStream(new File(target));
        ) {
            byte[] buffer = new byte[8192];
            while (inputStream.read(buffer) != -1) { // 将source文件数据读取出来,并存放至buffer中
                // 将buffer的数据写入至target文件中
                outputStream.write(buffer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

【文件流-复制案例】

package org.toast.io;

import java.io.*;

/**
 * @author toast
 * @time 2024/3/30
 * @remark
 */
public class TestCopyDemo {

    public static void main(String[] args) {
        String source = "src/main/resources/image/哆啦A梦.webp";
        String target = "src/main/resources/image/哆啦A梦_copy.webp";
        copy(source, target);
    }

    /**
     * 复制功能
     * @param source 源文件
     * @param target 目标文件
     */
    public static void copy(String source, String target) {
        copy(new File(source), new File(target));
    }

    public static void copy(File source, File target) {
        try {
            copy(new FileInputStream(source), new FileOutputStream(target));
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    public static void copy(InputStream inputStream, OutputStream outputStream) {
        try {
            int buffer = 0;
            while ((buffer = inputStream.read()) != -1) {
                outputStream.write(buffer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

3.2 内存流 ByteArrayInputStream&ByteArrayOutputStream

       java IO流处理中除了提供对文件进行数据的输入与输出,还提供对内存的数据进行输入与输出。

        内存流,以内存作作为数据存储介质,并提供数据输入输出操作。

        当需要从数据存储介质(内存)中读取数据,可以使用ByteArrayInputStream将数据读取出来。

        当需要将数据保存至数据存储介质(内存)时,可以使用ByteArrayOutputStream将数据写入数据存储介质(内存)

因为现在的数据存储介质是内存,所以用内存流。

【内存流-读写案例】

package org.toast.io.bytearray;

import java.io.*;

/**
 * @author toast
 * @time 2024/3/30
 * @remark
 */
public class TestByteArrayOutputStream {
    public static void main(String[] args) {
        String data = "内存流的意义;在一些复杂的业务当中有时候并不想用文件作为数据存储介质进行业务数据的处理,更像存储至内存进行处理像登录验证码之类的" +
                "直接放入存储即可。并且数据又是临时的,还要进行一次删除处理";
        String target = "src/main/resources/test/demo-file_byte_out.txt";
        byte[] buffer = data.getBytes();
        try {
            /**
             * 将data数据存储至内存流;可以这样简单的理解;
             * 因为data字符串本身就在内存里面。Stream只是提供一个通道,支持从内存读写数据;
             * 文件也是一样的,文件数据本身就在文件里面,只是通过Stream(FileInputStream/FileOutputStream)搭建一个通道,支持从文件里面进行数据读写。
             * 所以为什么要关闭流。就是关闭通道。因为通道资源有限,当所有通道都被占用;后面需要使用通道时;(等待其他通道释放)将无法正常进行数据的读写处理。
              */
            ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer);// 初始化大小和内容一样
            /**
             * 将data内存里面的数据最终写入到demo-file_byte_out.txt 文件里面;
             * 可以理解成从一个数据存储介质(内存) 到另外一个数据存储介质(文件)
             */
            FileOutputStream outputStream = new FileOutputStream(new File(target));
            int contentBuffer = 0;
            while ((contentBuffer = inputStream.read()) != -1 ) {
                outputStream.write(contentBuffer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.3 管道流  PipedOutputStream&PipedInputStream

        在讲文件流和内存流时,我们用数据存储介质来说明数据存储的不同。那管道流也是一样的概念吗?将数据存储至管道之中进行操作处理?这样有点异类。

        管道的概念,在计算机里面原本时是进程与进程之间信息数据通讯时需要建立的通讯管道。在java里面,java里面它强调是不同线程之间通讯。所以,管道流是用来处理不同线程之间数据的通讯问题。管道流有两种数据格式一种是字节流(PipedOutputStream, PipedInputStream),一种是字符流(PipedReader,PipedWriter)。

【管道流-线程讯通案例】

package org.toast.io.piped;

import java.io.IOException;
import java.io.PipedOutputStream;

/**
 * @author toast
 * @time 2024/3/30
 * @remark 发送线程
 */
public class SendThread implements Runnable {
    private PipedOutputStream out = new PipedOutputStream();

    @Override
    public void run() {
        String sendContent = "《中华人民共和国教育法》第四十五条规定:“学生应当认真听讲,按时完成学习任务,遵守学校规章制度”";
        try {
            this.out.write(sendContent.getBytes());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public PipedOutputStream getOut() {
        return this.out;
    }
}
package org.toast.io.piped;

import java.io.IOException;
import java.io.PipedInputStream;

/**
 * @author toast
 * @time 2024/3/31
 * @remark 接受线程
 */
public class ReceiveThread implements Runnable {
    private PipedInputStream input = new PipedInputStream();
    @Override
    public void run() {
        try {
            byte[] buffer = new byte[1024];
            int len = this.input.read(buffer);
            System.out.println("【接受消息】" + new String(buffer, 0, len));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public PipedInputStream getInput() {
        return this.input;
    }
}
package org.toast.io.piped;

import java.io.IOException;

/**
 * @author toast
 * @time 2024/3/30
 * @remark
 */
public class TestPipedDemo {

    public static void main(String[] args) throws IOException {
        SendThread send = new SendThread();
        ReceiveThread receive = new ReceiveThread();
        send.getOut().connect(receive.getInput());
        Thread sendThread = new Thread(send);
        Thread receiveThread = new Thread(receive);
        sendThread.start();
        receiveThread.start();
    }
}

程序执行结果

3.4 随机文件读取 java.io.RandomAccessFile

        在进行文件数据读取的时候,都是从头到尾进行数据的读取,对于一些特殊的要求,比如选择性读取文件中的内容。则普通的读取是从头开始遍历无法直接锁定。而RandomAccessFile类提供该功能,随机读写功能。

        随机读写功能实际上就相当于在整个文件中设置有一个文件读取的指针,每次读取的时候都会依据指针所在的位置进行指定长度数据的读取,如果要读取某一条数据,那么只需要修改指针的文件即可,这样的读取操作被称为随机文件读取


public class RandomAccessFile implements DataOutput, DataInput, Closeable {}

       通过RandomAccessFile 类的定义来看,其实现了DataOutput, DataInput接口,那么也就意味着RandomAccessFile 类同时具有读和写两种功能,来观察RandomAccessFile类中的方法。

【随机文件读取-案例】

package org.toast.io.randomaccess;

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

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class TestRandomAccessFileDemo {
    private static final int MAX_LENGTH = 8;

    private static final String PATH = "src/main/resources/test/random-access.txt";

    public static void main(String[] args) {
        write(); // 初始化,写入数据
        read(); // 读取文件中指定数据
    }


    public static void write() {
        try {
            File file = new File(PATH);
            RandomAccessFile raf = new RandomAccessFile(file, "rw"); // 读写模式进行输出
            String names[] = new String[]{"zhangsan", "lisi", "wangwu", "zhaoliu", "sunqi"};
            int ages[] = new int[]{17, 18, 16, 19, 20};
            for (int x = 0; x < names.length; x++) {
                String name = addEscape(names[x]);
                raf.write(name.getBytes()); // 输出8位的字节
                raf.writeInt(ages[x]); // 输出4位的整数
            }
            raf.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void read() {
        File file = new File(PATH);
        try {
            if (file.exists()) {
                RandomAccessFile raf = new RandomAccessFile(file, "r"); // 采用读模式 进行处理
                {   // 读取“lisi”的数据,属于第2条内容
                    raf.skipBytes(12); // 跨过12个字节
                    byte data[] = new byte[MAX_LENGTH]; // 姓名的长度统一为8位
                    raf.read(data); // 读取姓名数据到字节数组之中
                    int age = raf.readInt(); // 读取整型
                    System.out.printf("【第2条数据】姓名:%s、年龄:%d\n", new String(data).trim(), age);
                }
                {   // 读取“lisi”的数据,属于第1条内容
                    raf.seek(0); // 回到指定的索引位置
                    byte data[] = new byte[MAX_LENGTH]; // 姓名的长度统一为8位
                    raf.read(data); // 读取姓名数据到字节数组之中
                    int age = raf.readInt(); // 读取整型
                    System.out.printf("【第1条数据】姓名:%s、年龄:%d\n", new String(data).trim(), age);
                }
                {   // 读取“sunqi”第5条数据
                    raf.skipBytes(36); // 跨过12个字节
                    byte data[] = new byte[MAX_LENGTH]; // 姓名的长度统一为8位
                    raf.read(data); // 读取姓名数据到字节数组之中
                    int age = raf.readInt(); // 读取整型
                    System.out.printf("【第5条数据】姓名:%s、年龄:%d\n", new String(data).trim(), age);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static String addEscape(String val) {
        StringBuffer buffer = new StringBuffer(val);
        while (buffer.length() < MAX_LENGTH) {
            buffer.append(" "); // 在内容后追加空格
        }
        return buffer.toString();
    }
}

writer()方法在数据初始化时,内容不够8位时会自动填充 " " 空字符串内容;所以才会有NULL占位符表示

3.5 打印流 PrintStream&PrintWriter

        使用打印流更多的是关注于具体数据的输出,也就是说具体的字符串或者是数字,PrintWriter比PrintStream支持的操作要多很多很多,意味着PrintWriter在开发中更加方便。

【打印流-案例】

package org.toast.io.print;

import java.io.OutputStream;

/**
 * @author toast
 * @time 2024/3/31
 * @remark 自定义打印工具类
 */
public class PrintUtil implements AutoCloseable {
    private OutputStream output;

    public PrintUtil(OutputStream output) {
        this.output = output;
    }

    public void print(String str) {
        try {
            this.output.write(str.getBytes()); // 实现字符串输出
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void println(String str) {
        print(str + "\n");
    }

    public void print(byte num) {
        this.print(String.valueOf(num));
    }

    public void println(byte num) {
        this.println(String.valueOf(num));
    }

    public void print(short num) {
        this.print(String.valueOf(num));
    }

    public void println(short num) {
        this.println(String.valueOf(num));
    }

    public void print(int num) {
        this.print(String.valueOf(num));
    }

    public void println(int num) {
        this.println(String.valueOf(num));
    }

    public void print(long num) {
        this.print(String.valueOf(num));
    }

    public void println(long num) {
        this.println(String.valueOf(num));
    }

    public void print(float num) {
        this.print(String.valueOf(num));
    }

    public void println(float num) {
        this.println(String.valueOf(num));
    }

    public void print(double num) {
        this.print(String.valueOf(num));
    }

    public void println(double num) {
        this.println(String.valueOf(num));
    }

    public void print(boolean bool) {
        this.print(String.valueOf(bool));
    }

    public void println(boolean bool) {
        this.println(String.valueOf(bool));
    }

    public void print(char c) {
        this.print(String.valueOf(c));
    }

    public void println(char c) {
        this.println(String.valueOf(c));
    }

    public void println(Object obj) {
        this.println(obj.toString());
    }

    @Override
    public void close() throws Exception {
        this.output.close();
    }
}
package org.toast.io.print;

import java.io.File;
import java.io.FileOutputStream;

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class PrintDemo {

    public static void main(String[] args) throws Exception {
        String path = "src/main/resources/test/random-print.txt";
        File file = new File(path) ;
        PrintUtil pu = new PrintUtil(new FileOutputStream(file)) ; // 向文件中输出
        pu.print("姓名:");
        pu.println("TOAST");
        pu.println("吐司面包~~~~~~") ;
        pu.close();
    }
}

        上面案例是自定义的打印工具类;下面是java.io包下提供的PrintWriter打印工具类(也就是字符打印流)还有一个PrintStream(字节打印流)

这个是字节打印流

3.6 System类对IO的支持

        在刚接触Java是使用的就是System.out.println();方法,这个System类里面的out用的是什么?并且System提供in, out, err 三个流的处理。

public static final InputStream in
表示标准的键盘输入
public static final PrintStream out
表示进行信息的输出
public static final PrintStream err
表示的是错误的输出

java中常量名称都是大写,这里为什么都是小写,因为是早期设计没有现代这种常量命名规范;

首先源码当中这三个对象都为null,其势力对象是由JVM来进行实例化的。

Java中输出对象的时候,不管对象是否调用了toString() 其都会调用toString(); 其原因和PrintStream打印类分不开;看源码分析

【System.in - 键盘输入案例】

package org.toast.io.print;

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

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class KeyBoardInputDemo {
    
    public static void main(String[] args) throws IOException {
        InputStream keyBoardInput = System.in;
        System.out.println("请输入要发送的数据信息:");
        byte[] data = new byte[16];
        int len = keyBoardInput.read(data);
        System.out.println("【展示键盘输入的内容】" + new String(data, 0, len));
    }
}

3.7 BufferedReader缓冲输入流

        BufferedReader 缓冲输入流,目的是为输入流提供一个缓冲区,将读取到的数据存储至缓冲区里面。简化了将读取的数据手动创建一个数组进行存放;这个缓冲输入流内部提供一个缓冲区存储内容;打红框框都简化了交由BufferedInputStream维护。

那BufferedReader 缓冲输入流的缓冲是怎么实现?看源码

【BufferedReader-键盘输入案例】

package org.toast.io.bufferedreader;

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

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class BufferedReaderDemo {

    public static void main(String[] args) throws IOException {
        BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in)) ;
        System.out.print("请输入你要发送的信息:"); // 信息发送完毕一定要输入回车
        String str = keyboard.readLine() ; // 以回车为分隔符
        System.out.println("【数据回显】" + str);
    }
}

3.8 Scanner输入流

        使用Scanner的时候可以直接实现 InputStream对象实例的接收,那么下面就利用Scanner实现一个键盘数据输入的处理逻辑。

【Scanner-案例1】

package org.toast.io.scanner;

import java.util.Scanner;

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in) ;
        System.out.print("请输入要发送的信息:");
        if (scanner.hasNext()) {    // 有数据输入
            String value = scanner.next() ; // 获取数据内容
            System.out.println("回显输入数据:" + value);
        }
    }
}

【Scanner-案例2】

package org.toast.io.scanner;

import java.util.Scanner;

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in) ;
        System.out.print("请输入您的年龄:");
        if (scanner.hasNextInt()) {    // 有整数输入
            int value = scanner.nextInt() ; // 获取数据内容
            System.out.println("回显输入数据:" + value);
        } else {
            System.err.println("【ERROR】输入的内容不是数字。");
        }
    }
}

package org.toast.io.scanner;

import java.util.Scanner;

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in) ;
        System.out.print("请输入注册邮箱:");
        if (scanner.hasNext("\\w+@\\w+\\.\\w+")) {    // 有符合指定正则规范的信息输入
            String value = scanner.next("\\w+@\\w+\\.\\w+") ; // 获取数据内容
            System.out.println("回显输入数据:" + value);
        } else {
            System.err.println("【ERROR】输入数据的格式不正确。");
        }
    }

    private static void demo2() {
        Scanner scanner = new Scanner(System.in) ;
        System.out.print("请输入您的年龄:");
        if (scanner.hasNextInt()) {    // 有整数输入
            int value = scanner.nextInt() ; // 获取数据内容
            System.out.println("回显输入数据:" + value);
        } else {
            System.err.println("【ERROR】输入的内容不是数字。");
        }
    }

    private static void demo1() {
        Scanner scanner = new Scanner(System.in) ;
        System.out.print("请输入要发送的信息:");
        if (scanner.hasNext()) {    // 有数据输入
            String value = scanner.next() ; // 获取数据内容
            System.out.println("回显输入数据:" + value);
        }
    }
}

        Scanner在BufferedReader基础之上提供了相对应类型判断处理;类型处理包含如下图

等等,相比较BufferedReader而言减少大量类型转换的处理。

【Scanner-案例3】

        分隔符可以随时切换,可以是 \n, 也可以是,也可以是 空格;如果是BufferedInputStream只支持 \n 分隔符;切换不支持替换。

package org.toast.io.scanner;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class ScannerDemo {
    public static void main(String[] args) throws FileNotFoundException {
        String path = "src/main/resources/test/demo-scanner.txt";
        Scanner scanner = new Scanner(new File(path)) ;
        scanner.useDelimiter(" ") ; // 使用换行作为读取分隔符
        while (scanner.hasNext()) { // 只要存在有数据行,那么就进行内容的获取
            String value = scanner.next() ; // 接收数据内容
            System.out.println(value);
        }
    }
}

四,字符流

 4.1 转换流

        java.io 包提供了数据输入与输出的标准,数据类型有字节和字符。在一些业务场景中两种不同类型的数据流之间的互相转换问题。所以java.io包下也提供转换流。

public class OutputStreamWriter extends Writer {

    /**
     *
     * 从构造方法可以看出流的转换,是从构造方法开发接受字节流;原因它本身就继承Writer 是一个字符流
     */
    public OutputStreamWriter(OutputStream out, String charsetName)
        throws UnsupportedEncodingException
    {
        super(out);
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
    }


    public OutputStreamWriter(OutputStream out) {
        super(out);
        se = StreamEncoder.forOutputStreamWriter(out, this,
                Charset.defaultCharset());
    }

    public OutputStreamWriter(OutputStream out, Charset cs) {
        super(out);
        if (cs == null)
            throw new NullPointerException("charset");
        se = StreamEncoder.forOutputStreamWriter(out, this, cs);
    }


    public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
        super(out);
        if (enc == null)
            throw new NullPointerException("charset encoder");
        se = StreamEncoder.forOutputStreamWriter(out, this, enc);
    }
}
public class InputStreamReader extends Reader {

    private final StreamDecoder sd;


    public InputStreamReader(InputStream in) {
        super(in);
        sd = StreamDecoder.forInputStreamReader(in, this,
                Charset.defaultCharset()); // ## check lock object
    }

    public InputStreamReader(InputStream in, String charsetName)
        throws UnsupportedEncodingException
    {
        super(in);
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
    }

    public InputStreamReader(InputStream in, Charset cs) {
        super(in);
        if (cs == null)
            throw new NullPointerException("charset");
        sd = StreamDecoder.forInputStreamReader(in, this, cs);
    }

    public InputStreamReader(InputStream in, CharsetDecoder dec) {
        super(in);
        if (dec == null)
            throw new NullPointerException("charset decoder");
        sd = StreamDecoder.forInputStreamReader(in, this, dec);
    }
}

        从代码和继承和继承图中,可以得出。流的转换是通过从构造方法传入字节流,因为这两个转换流本身就属于字符流。所以字节转换字符在该类里面进行完成。

【转换流-字节转字符案例】

package org.toast.io.convertio;

import java.io.*;

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
public class StreamReaderDemo {

    public static void main(String[] args) throws IOException {
        File file = new File("src/main/resources/test/demo-file-convert.txt") ;
        Reader in = new InputStreamReader(new FileInputStream(file)) ;
        char [] data = new char[1024] ;
        int len = in.read(data);
        System.out.println(new String(data, 0, len));
        in.close();
    }
}

        

五,对象序列化   java.io.ObjectOutputStream & java.io.ObjectInputStream

        对象序列化,就是将存储在堆内存的对象的内容取出,并且将其直接转换为二进制数据流,通过网络转换可以给其他程序使用,使用之前进行还原处理。

        在Java之中,并不是所有类都具有序列化的能力,需要实现java.io.Serializable接口;该接口没有任何方法,是一种标识性的接口,表示一种处理能力的接口。

        序列化当中,为了保证反序列号的正确性,一般都需要一个序列号版本号,serialVersionUID。现在可以不用手动分配一个;因为会自动分配一个序列化版本号。

【对象序列化-案例】

package org.toast.io.serial;

import java.io.*;

/**
 * @author toast
 * @time 2024/3/31
 * @remark
 */
class Book implements Serializable { // 本类的对象可以序列化处理
    private String title ;
    private String author ;
    private double price ;
    public Book(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }
    public String toString() {
        return "【图书】名称:" + this.title + "、作者:" + this.author + "、价格:" + this.price ;
    }
}

public class SerialDemo {
    private static final File BINARY_FILE = new File("src/main/resources/test/demobook.serToask") ;

    public static void main(String[] args) throws Exception {
        serial(new Book("《意志力》", "约翰·蒂尔尼", 0));
    }

    public static void serial(Object object) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(BINARY_FILE)) ; // 文件序列化
        oos.writeObject(object); // 序列化输出
        oos.close();
    }

    public static Object deserial() throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(BINARY_FILE)) ; // 对象输入流
        Object data = ois.readObject() ; // 反序列化对象
        ois.close();
        return data ;
    }
}

        数据写入指定的文件当中里面去了。

进行反序列

transient关键字

        序列化处理的时候实际上是将一个对象中所有的属性内容实现了二进制的数据存储,但是如果说现在某些属性不希望被序列化下来,那么这个时候在属性使用transient关键字即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值