关于IO流

IO流的分类

根据流方向分为输入流、输出流
根据操作的内容的不同可以分为字符流、字节流

得到四大基本流:

输入流输入流
字符流ReaderWriter
字符流InputStreamOutputStream

这四大基本流都是抽象的,使用时通常使用这些抽象类的具体实现类

整个IO流体系
在这里插入图片描述

字符输入流

Reader -> InputStreamReader -> FileReader

部分构造方法:

FileReader(File file)

创建一个新的 FileReader ,给出 File读取。

FileReader(String fileName)

创建一个新的 FileReader ,给定要读取的文件的名称。

重要方法:

int read():读一个字符。

int read(char[] cbuf):将字符读入数组。

abstract int read(char[] cbuf, int off, int len):将字符读入数组的一部分。

abstract void close():关闭流并释放与之相关联的任何系统资源。

为什么read 方法返回的不是char 而是 int ?

因为如果返回的是char ,则为无法用任意的char 表示到达了文件的结尾,所以此处不能返回char 而是返回int 类型。正常情况下返回的是正数,强转为char 则得到对应的字符,当达到文件结尾时返回-1表示。

字符输出流

Writer -> OutputStreamWriter -> FileWriter

部分构造方法

FileWriter(File file)

给一个File对象构造一个FileWriter对象。

FileWriter(File file, boolean append)

给一个File对象构造一个FileWriter对象。

FileWriter(String fileName)

构造一个给定文件名的FileWriter对象。

FileWriter(String fileName, boolean append)

构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。

通过boolean的append参数,可以指定数据是否追加,如果传入false(默认就是false)则,会产生新的文件覆盖旧的文件,如果传入true,则在原有文件的基础上进行追加。

重要方法:

abstract void close()

关闭流之前先刷新。

abstract void flush()

刷新该流的缓冲。

void write(char[] cbuf)

写入一个字符数组。

abstract void write(char[] cbuf, int off, int len)

写入字符数组的一部分。

void write(int c)

写一个字符

void write(String str)

写一个字符串

void write(String str, int off, int len)

写一个字符串的一部分。

在输出数据时,有部分数据可能会缓冲在流的内部,通过调用flush()方法可以强制刷新流,将缓存在流内部的数据刷出去,所以在做writer()方法之后,最好做一次flush()冲刷。

调用close()方法时,close方法内部会隐含的进行一次flush(),防止在关流时有数据死在缓冲区。

字节输出流

OutputStream -> FileOutputStream

构造方法:

FileOutputStream(File file)

创建文件输出流以写入由指定的 File对象表示的文件。

FileOutputStream(File file, boolean append)

创建文件输出流以写入由指定的 File对象表示的文件。

FileOutputStream(String name)

创建文件输出流以指定的名称写入文件。

FileOutputStream(String name, boolean append)

创建文件输出流以指定的名称写入文件。

通过boolean的append参数,可以指定数据是否追加,如果传入false(默认就是false)则,会产生新的文件覆盖旧的文件,如果传入true,则在原有文件的基础上进行追加。

重要方法:

void close()

关闭此输出流并释放与此流相关联的任何系统资源。

void flush()

刷新此输出流并强制任何缓冲的输出字节被写出。

void write(byte[] b)

将 b.length字节从指定的字节数组写入此输出流。

voidwrite(byte[] b, int off, int len)

从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。

在利用输出流输出数据的过程中,流的底层具有缓冲机制提升效率,但同时也有可能造成部分数据堆积在底层流的缓冲区中,一时无法写出,此时可以调用flush()方法,手动的将流中缓冲的数据写出。

close()方法关闭流,在关闭流的过程中,会隐含的调用一次flush() 保证不会有数据死在缓冲区里。

流中的异常处理

1、要将流对象放到try之外定义并且赋值为null,放到try之内创建。
2、在关流之前需要判断是否为空。
3、关流之后需要将流对象强制置为null。
4、写完数据之后需要手动冲刷一次缓冲区。

自定义缓冲区

对于字符流是自定义一个char 类型的数组作为缓冲区

对于字节流是自定义一个byte 类型的数组作为缓冲区

这样一次拷贝一个数组,来提升新能。

@Test
    public void test4(){
        File file1 = new File("E:\\Intellij IDEA\\javaTest\\src\\demo_17\\s1.txt");
        File file2 = new File("E:\\Intellij IDEA\\javaTest\\src\\demo_17\\s2.txt");
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream(file1);
            outputStream = new FileOutputStream(file2);
             // 创建一个字节数组作为缓冲区 
            byte[] bytes = new byte[5];
            // 定义一个变量表示读取的字节个数 
            int len = 0;
            while ((len = inputStream.read(bytes))!=-1){
                outputStream.write(bytes,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (outputStream!=null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream!=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

缓冲流

java 中提供了自带缓冲区的流BufferedReader、BufferedWriter,用于装饰其他流,提升读写性能,并提供了新的方法。利用FileReader来构建了BufferedReader,然后再BufferedReader对读取功能做了增强,这种方式称之为装饰设计模式 —- 利用了同类对象构建自己对象本身,对对象身上的功能做了增强或者改善。

BufferedWriter提供了一个更大的缓冲区,能到很大的提升复制的效率。

public class BufferedRead erextends Reader

构造方法:

BufferedReader(Reader in)

创建使用默认大小的输入缓冲区的缓冲字符输入流。

BufferedReader(Reader in, int sz)

创建使用指定大小的输入缓冲区的缓冲字符输入流。

重要方法:

int read()

读一个字符

int read(char[] cbuf, int off, int len)

将字符读入数组的一部分。

StringreadLine()

读一行文字。

void close()

关闭流并释放与之相关联的任何系统资源。

public class BufferedWriter extends Writer

构造方法:

BufferedWriter(Writer out)
创建使用默认大小的输出缓冲区的缓冲字符输出流。

BufferedWriter(Writer out, int sz)
创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。

重要方法:

void close()

关闭流,先刷新。

void flush()

刷新流。

void newLine()

写一行行分隔符。

void write(char[] cbuf, int off, int len)

写入字符数组的一部分。

void write(int c)

写一个字符

void write(String s, int off, int len)

写一个字符串的一部分。

	 /**
     * 字节缓冲流实现文本的复制
     */
    @Test
    public void test5(){
        File file1 = new File("E:\\Intellij IDEA\\javaTest\\src\\demo_17\\s1.txt");
        File file2 = new File("E:\\Intellij IDEA\\javaTest\\src\\demo_17\\s3.txt");
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
            FileInputStream fis = new FileInputStream(file1);
            FileOutputStream fos = new FileOutputStream(file2);

            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);

            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (bos!=null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bis!=null){
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

字节流和字符流的桥梁 - 转换流

转换流概述:

字符流底层也是字节流,只不过在字节流的基础上增加了缓冲区和编解码器。

字符流内置的编解码器默认采用的编码集是系统码,并且无法修改。

这在使用字符流读入非系统码的字符数据集时就会造成乱码。

此时无法通过字符流来解决,java 提供了转换流,可以字节编写字节流来读取数据,再通过转换流转换为字符流,并在这个过程中手动指定码表,从而实现指定码表的自定义字符流。

public class InputStreamReader extends Reader

部分构造方法:

InputStreamReader(InputStream in)

创建一个使用默认字符集的 InputStreamReader。

InputStreamReader(InputStream in, String charsetName)

创建使用指定字符集的 InputStreamReader。

public class OutputStreamWriter extends Writer

部分构造方法:

OutputStreamWriter(OutputStream in)

创建一个使用默认字符集的 OutputStreamWriter。

OutputStreamWriter(OutputStream in, String charsetName)

创建使用指定字符集的 OutputStreamWriter。
图解:
在这里插入图片描述
实例:

拷贝一个utf-8编码集包含中文的文本文件 要求产生的文件是gbk编码。

/**
     * 转换流
     *
     *  案例:通过转换流 生成自定义码表的字符流
     *  复制文件 将utf-8文件转换为gbk格式的文件
     */
    @Test
    public void test6(){
        File file1 = new File("E:\\Intellij IDEA\\javaTest\\src\\demo_17\\s1.txt");
        File file2 = new File("E:\\Intellij IDEA\\javaTest\\src\\demo_17\\s3.txt");

        InputStreamReader inputStreamReader = null;
        OutputStreamWriter outputStreamWriter = null;

        try {
            // 1.创建字节流
            FileInputStream fis = new FileInputStream(file1);
            FileOutputStream fos = new FileOutputStream(file2);
            // 2.创建转换流 将字节流转换为字符流 并显式指定码表为utf-8
            inputStreamReader = new InputStreamReader(fis,"utf-8");
            outputStreamWriter = new OutputStreamWriter(fos,"utf-8");

            char[] chars = new char[1024];
            int len = 0;
            while ((len = inputStreamReader.read(chars)) != -1){
                outputStreamWriter.write(chars,0,len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (inputStreamReader!=null){
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (outputStreamWriter!=null){
                try {
                    outputStreamWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

对象流-序列化与反序列化

对象的序列化

  • 凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
    private static final long serialVersionUID;
    serialVersionUID用来表明类的不同版本间的兼容性。 简言之,其目的是以序列化对象
    进行版本控制,有关各版本反序列化时是否兼容。
    如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自
    动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,
    显式声明。

  • 简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验
    证版本一致性的。
    在进行反序列化时,JVM会把传来的字节流中的
    serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同
    就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异
    常。(InvalidCastException)

  • 由于大部分作为参数的类如String 、Integer 等都实现了java.io.Serializable 的接口,也可以利用多态的性质,作为参数使接口更灵活。

 /** 序列化*/
    @Test
    public void test7(){
        File file1 = new File("E:\\Intellij IDEA\\javaTest\\src\\demo_17\\s1.txt");

        ObjectOutputStream objectOutputStream = null;

        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream(file1));
            objectOutputStream.writeObject(new Persion(1,"张三"));
            objectOutputStream.flush();
            objectOutputStream.writeObject(new String("李四"));
            objectOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (objectOutputStream!=null){
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 反序列化
     * */
    @Test
    public void test8() {
        File file1 = new File("E:\\Intellij IDEA\\javaTest\\src\\demo_17\\s1.txt");
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(new FileInputStream(file1));
            
            Persion persion = (Persion) objectInputStream.readObject();
            String s  = (String) objectInputStream.readObject();


            System.out.println(persion);
            System.out.println(s);
        } catch (IOException e) {
            e.printStackTrace();
        }catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            if (objectInputStream!=null){
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值