Java SE-IO操作二

IO流概述
字节流
文件复制
字符流
IDK9新特性
Properties类
转换流
序列化和反序列化
打印流

IO流概述
输入输出流顶级父类

在这里插入图片描述

字节流
  • 一切皆为字节:一切数据都是以二进制行式保存
FileOutputStream类
  • 注意:GBK中二个字节是一个中文,UTF-8中三个字节是一个中文
  • 向文件中写入一个字节图解
  • 构造方法作用:
  • 会根据构造方法中传递的文件路径,创建空的文件
  • 会把FileOutputStream对象指向创建好的文件
  • 写入数据的原理(内存-》硬盘)
  • Java程序-》jvm虚拟机-》OS(操作系统)-》OS调用写数据的方法-》把数据写入到文件中
向文件中写入一个字节
    /**
     *  向文件中写入一个字节
     *    public void write(int n);
     */
    public static void show() {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("a.txt");
            /**
             *   在文件中会显示a  用了记事本原理
             *     写入97时会以二进制行式存储到硬盘,当记事本读取时会按照记事本原理显示
             */
            fos.write(97);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
向文件中一次写入多个字节
    /**
     *   public void write(byte[] bytes);
     *   一次向文件中写入多个字节
     *      如果写入的第一个字节是正数(0-127),那么现实的时候会查询ASCII码表
     *      如果写入的第一个字节是负数那么第一个字节和第二个字节,俩个字节会组成一个中文显示,查询系统默认码表(GBK)
     */
    public static void show2() {
        byte[] bytes = {48, 49, 50};  //文件中显示 012
        byte[] bytes1 = {-10, 3, -2, 5, 7};
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("b.txt");
            //向文件中写入整个字节数组
            fos.write(bytes);
            //先文件中写入部分字节数组
            fos.write(bytes, 0, 1);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
向文件中写入字符串
    /**
     * 写入字符的方法:可以使用String类中方法将字符串转换为字节数组
     */
    public static void show3() {
        String s = "你好";
        byte[] bytes = s.getBytes();
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("b.txt");
            //向文件中写入整个字节数组
            fos.write(bytes);
            //先文件中写入部分字节数组
            fos.write(bytes, 0, 1);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

在这里插入图片描述

向文件中续写数据
    /**
     *   追加写/续写
     *   FileOutputStream(String name, boolean append)   创建一个向指定名称的文件写入数据的文件输出流
     *   FileOutputStream(File file, boolean append) 创建一个向指定File对象文件中写入数据的文件输出流
     *       boolean append:追加写开关
     *           true:创建对象时不会覆盖原文件,继续在文件末尾追加数据
     *           false:创建一个新的 文件覆盖原文件
     *
     *    写换行:
     *      windows:\r\n
     *      linux:/n
     *      mac:/r
     */
    public static void show() {
        FileOutputStream fos = null;
        String s = "你好";
        try {
            fos = new FileOutputStream("d.txt");
            //在文件中写入10个换行的你好
            for (int i = 0; i < 10; i++) {
                fos.write(s.getBytes());
                //写入换行符
                fos.write("\r\n".getBytes());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
一次读取多个字节原理

在这里插入图片描·述

FileInputStream类
  • 从文件读出数据原理

在这里插入图片描述

  • 构造方法作用
  • 创建一个FileInputStream对象
  • 会把FileInputStream对象指定构造方法中要读取的文件
  • 读取数据的原理(硬盘-》内存)
  • Java程序-》JVM-》OS->OS读取数据的方法-》读取文件
  • 使用步骤
  • 创建FileInputStream对象
  • 使用read方法读取数据
  • 关闭流
从文件中读取一个字节
    /**
     *   从文件中一个一个读取字节
     */
    public static void show () {
        FileInputStream fis = null;
        try {
            //1、创建对象
            fis = new FileInputStream("a.txt");
//            int len = fis.read();  //91
//            System.out.println(len);
//            len = fis.read();  //98
//            System.out.println(len);
//            len = fis.read();
//            System.out.println(len);

            //使用while循环读取
            /**
             *   这里注意必须要用一个变量来接受读取的数据否则会跳读
             */
            int len = 0;
            while ((len = fis.read()) != -1) {
                System.out.println(len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
从文件中一次读取多个字节
    /**  int read(byte[] bytes)
     *   将文件中数据读取到字节数组中,一次读取多个字节
     *      参数:byte[]数组的作用,起到缓冲作用,存储每次读取的字节
     *            int len 每次读取字节的长度一般为1024字节
     */
    public static void show2 () {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("b.txt");
//            byte[] bytes = new byte[2];
//            int len = fis.read(bytes);   //len代表每次读取字节的个数
//            System.out.println(new String(bytes));

            //循环输出读出的数据
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = fis.read(bytes)) != -1) {
                //System.out.println(new String(bytes));  //此时会输出空格,因为字节数组长度为1024
                System.out.println(new String(bytes, 0, len));  //使用此方法输出无空格
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

文件复制
文件复制原理

在这里插入图片描述

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

public class Demo04FileCopy {
    /**
     *     文件复制原理:
     *         从一个文件中读出,再写入另一个文件
     */
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("D:\\324.01.jpg");
        FileOutputStream fos = new FileOutputStream("D:\\b.jpg");
        //从文件中读取
        byte[] bytes = new byte[1024];
        int len;
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
        }
        fis.close();
        fos.close();
    }
}

字符流
使用字节流读取字节文件
  • 读取一个中文
  • GBK占2俩个字节
  • UTF-8占3个字节
  • 为了避免字节流当每次读取一个字节时会产生错误使用字符流
字符输出流
import java.io.FileWriter;
import java.io.IOException;

/**
 *   字符输入流
 *      构造方法:
 *          FileWriter(String name);
 *          FileWriter(File file);
 *      作用:
 *          创建一个FileWriter对象
 *          根据构造方法的文件/文件路径,创建文件
 *          将FileWriter对象指向创建好的文件
 *      使用步骤:
 *          创建FileWriter对象
 *          调用write方法将数据写入到内存缓冲区(字符转换为字节的过程)
 *          调用flush方法,将内存缓冲区中的数据,写入到文件中
 *          释放资源(会先把内存缓冲区的数据刷新到文件中)
 *
 */
public class Demo01FileWriter {
    public static void main(String[] args) throws IOException {
        FileWriter fr = new FileWriter("b.txt");
        //将数据写入到内存缓冲区
        fr.write(97);
        //将数据从内存缓冲区刷新到文件中
        fr.flush();
        //关闭资源(此时会自动将数据刷新到文件中)
        fr.close();
    }
}

/**
 *    写数据的其它方法:
 *         void write(char[] buf) ;  写入字符数组
 *         void write(char ch);  //写入字符
 *         void write(char[] buf, int off, int len);  写入部分字符数组
 *         void write(String string);  写入字符串
 */
public class Demo03WriteMethod {
    public static void main(String[] args) throws IOException {
        char[] chars = {'a', 'b', 'c', 'd'};
        FileWriter fr = new FileWriter("a.txt");
        //写入一个字符到缓冲区
        fr.write(97);
        //写入字符数组到缓冲区
        fr.write(chars);
        //写入字符数组部分到缓冲区
        fr.write(chars, 0, 2);
        //写入字符串到缓冲区
        fr.write("传智播客");
        //写入字符串部分到缓冲区
        fr.write("程序员",0 ,3);
        //刷新数据到文件中
        fr.flush();
        fr.close();
    }
}

续写和换行
/**
 *   续写和换行
 *       FileWriter(String name, boolean append)   创建一个向指定名称的文件写入数据的文件输出流
 *       FileOWriter(File file, boolean append) 创建一个向指定File对象文件中写入数据的文件输出流
 *    换行:
 *       windows:\r\n
 *       linux:/n
 *       mac:/r
 */
public class Demo04WriteMethod {
}
字符输出流和字节输出流最大区别
  • 字节输出流将数据写入到文件中
  • 字符输出流将文件写入到缓冲区
close方法和flush方法区别
/**
 *   close方法和flush方法区别:
 *       close:先刷新缓冲区,然后再通知系统释放资源,该对象不能再被使用了
 *       flush:刷新缓冲区,该对象可以继续被使用
 */
JDK7新特性
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 *    JDK7新特性
 *       再try后面可加一个(),在括号里定义流对象
 *       那么这个流对象的作用域就在try中有效
 *       try代码执行完毕,会自动将流对象释放,不用再写finally
 *        格式:
 *           try(定义流对象;定义流对象......) {
 *               可能会抛出异常的代码
 *           } catch(异常类变量 变量名) {
 *               异常的处理逻辑
 *           }
 */
public class Demo05JDK {
    public static void main(String[] args) {

        try (
                FileInputStream fis = new FileInputStream("D:\\324.01.jpg");
                FileOutputStream fos = new FileOutputStream("D:\\b.jpg");) {

            //从文件中读取
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
JDK9新特性
/**
 *    jdk9新特性
 *       在try前面可以定义流对象
 *       在try后面的括号中可以直接引入流对象的名称(变量名)
 *       在try代码执行完毕,也可以直接释放掉,不用再写finally
 *       格式:
 *           A a = new A();
 *           B b = new B();
 *           try(a; b) {
 *  *               可能会抛出异常的代码
 *  *           } catch(异常类变量 变量名) {
 *  *               异常的处理逻辑
 *  *           }
 */       // 一般使用jdk7新特性,因为jdk9还要抛出异常
public class Demo06JDK {
    public static void main(String[] args) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("D:\\324.01.jpg");
        FileOutputStream fos = new FileOutputStream("D:\\b.jpg");
        try (fis; fos) {
            //从文件中读取
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
区别
  • 一般使用jdk7新特性,因为jdk9还要抛出异常
Properties类
/**
 * Properties 类
 *        extends Hashtable<Object,Object>Properties 类表示了一个持久的属性集,
 *        Properties 可保存在流中或从流中加载
 *        Properties集合是唯一一个与IO流相结合的集合
 *          可用Properties集合中的store方法,将集合中的临时数据,持久写入到磁盘中存储
 *          可用Properties集合中的load方法,把硬盘中的文件(键值对),读入到集合中
 *      属性列表中每个键和值对应的都是一个字符串
 *         Properties集合是一个双列集合,默认key和value都是字符串
 */
将磁盘文件数据读取存储到集合中
    /***
     *    使用Properties集合中的load方法,把硬盘中保存的文件(键值对),读取到集合中
     *         void load(Reader reader)
     *           按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)
     *         void load(InputStream inStream)
     *           从输入流中读取属性列表(键和元素对)。
     *    参数:
     *       OutputStream out  字节输入流,不能写中文
     *       Writer writer  字符输入流,可以写中文
     *     使用步骤:
     *        创建Properties集合对象
     *        调用load方法读取保存键值对的文件数据到集合中
     *        遍历集合
     *     注意:
     *        存储键值对的文件中,键与值默认的连接符号可以使用
     *        存储键值对的文件中,可以使用#作为注释,被注释的键值对不再被读取
     *        存储键值对的文件中,键与值默认都是字符串,不用再加引号
     */
    private static void show03() throws IOException {
        //创建集合对象
        Properties prop = new Properties();
        //将文件中数据读取到集合中保存
        prop.load(new FileReader("a.txt"));
        //遍历集合
        Set<String> set = prop.stringPropertyNames();
        for (String key : set) {
            String value = prop.getProperty(key);
            System.out.println(key + "=" + value);
        }
    }
将集合中数据存储到文件中
    /**
     *    使用Properties集合中的store方法,可将集合中的临时数据,持续化写入到磁盘中存储
     *        void store(OutputStream out, String comments);
     *        void store(Writer writer, String comments);
     *     参数:
     *        OutputStream out  字节输入流,不能写中文
     *        Writer writer  字符输入流,可以写中文
     *        String comments   注释,用来解释说明保存的文件是做什么用的
     *                           不能使用中文,会产生乱码,一般默认是UNICODE编码
     *                           一般不使用空字符串
     *      使用步骤:
     *          创建Properties集合对象,添加数据
     *          创建字节输出流/字符输出流对象,构造方法中要绑定的输出的目的地
     *          使用Properties集合中的store方法,把集合中的临时数据,持久化存储到磁盘中
     *          释放资源
     */
    private static void show02() {
        //1、创建集合对象
        Properties prop = new Properties();
        //向集合中添加数据
        prop.setProperty("马龙", "175");
        prop.setProperty("张继科", "180");
        prop.setProperty("樊振东", "170");

        //2、创建字符输入流对象
        FileWriter fr = null;
        try {
            fr = new FileWriter("a.txt");

            //3、将数据存储到文件中
            prop.store(fr, "save data");
        } catch (IOException e) {
            e.printStackTrace();
        }

        //4、释放资源
        prop.clone();
    }
字节缓冲输入流
  • 给基本的字节输入流增加一个缓冲区(数组)提高基本输入流的缓冲效率,字符缓冲输入流也是如此

在这里插入图片描述

/**
 *   java.io.BufferedInputStream extends InputStream
 *       继承自父类的成员方法
 *          abstract  int read()
 *           从输入流中读取数据的下一个字节。
 *          int read(byte[] b)
 *           从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
 *          int read(byte[] b, int off, int len)
 *           将输入流中最多 len 个数据字节读入 byte 数组。
 *          void close()
 *           关闭此输入流并释放与该流关联的所有系统资源。
 *       构造方法:
 *          BufferedInputStream(InputStream in)   创建一个BufferedInputStream并保存其参数,即输入流 in,以便蒋来使用
 *          BufferedInputStream(InputStream in, int size)  创建指定缓冲区大小 BufferedInputStream 并保存其参数,即输入流
 *       参数:
 *           可以传递一个FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream
 *           size:指定缓冲流大小,不指定默认
 *        使用步骤:
 *              创建BufferedInputStream对象
 *  *           创建BufferedInputStream对象
 *  *           调用BufferedInputStream对象的read()方法
 *  *           释放资源
 *         注意:当关闭资源时只需要关闭缓冲流资源就可以
 */
public class Demo02BufferedInputStream {
}

字节缓冲输出流
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 *    java.io.BufferedOutputStream extends OutputStream
 *        继承父类的共享成员方法:
 *            void close()
 *           关闭此输出流并释放与此流有关的所有系统资源。
 *            void flush()
 *           刷新此输出流并强制写出所有缓冲的输出字节。
 *            void write(byte[] b)
 *           将 b.length 个字节从指定的 byte 数组写入此输出流。
 *            void write(byte[] b, int off, int len)
 *           将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
 *            abstract  void write(int b)
 *           将指定的字节写入此输出流。
 *       构造方法:
 *           BufferedOutputStream(OutputStream out)
 *           创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
 *          BufferedOutputStream(OutputStream out, int size)
 *           创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
 *       参数:
 *          可以传递一个FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream
 *          size:指定缓冲流大小,不指定默认
 *        使用步骤:
 *           创建FileOutputStream对象
 *           创建BufferedOutputStream对象
 *           调用BufferedOutputStream对象的write()方法,把数据写入到缓冲区
 *           调用BufferedOutputStream对象的flush方法把内部缓冲区的数据,刷新到文件中
 *           释放资源
 */
public class Demo01BufferedOutputStream {
    public static void main(String[] args) {

        try {
            FileOutputStream fos = new FileOutputStream("a.txt");
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            bos.write("把数据写入到内存缓冲区".getBytes());
            //将内存缓冲区数据刷新到文件中
            bos.flush();
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
字符缓冲输入流
/**
 *   java.io.BufferedReader extends Reader
 *        int read()
 *           读取单个字符。
 *        int read(char[] cbuf, int off, int len)
 *           将字符读入数组的某一部分。
 *        void close()
 *           关闭该流并释放与之关联的所有资源。
 *      构造方法:
 *         BufferedReader(Reader in)
 *           创建一个使用默认大小输入缓冲区的缓冲字符输入流。
 *         BufferedReader(Reader in, int sz)
 *           创建一个使用指定大小输入缓冲区的缓冲字符输入流。
 *      参数:
 *         传递FileReader,给它增加一个缓冲区,提高FileReader的读取效率
 *      特有的成员方法:
 *         String readLine()
 *           读取一个文本行。
 *         返回值:包含该行内容的字符串,不包含任何终止符,如果已到达流末尾,则返回null
 */
public class Demo04BufferedReader {
}


字符缓冲输出流
/**
 *    java.io.BufferedWriter extends Writer
 *
 */

/**
 *  *        继承父类的共享成员方法:
 *  *            void close()
 *  *           关闭此输出流并释放与此流有关的所有系统资源。
 *  *            void flush()
 *  *           刷新此输出流并强制写出所有缓冲的输出字节。
 *  *            void write(byte[] b)
 *  *           将 b.length 个字节从指定的 byte 数组写入此输出流。
 *  *            void write(byte[] b, int off, int len)
 *  *           将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
 *  *            abstract  void write(int b)
 *  *           将指定的字节写入此输出流。
 *           构造方法:
 *              BufferedWriter(Writer out)
 *                创建一个使用默认大小输出缓冲区的缓冲字符输出流。
 *              BufferedWriter(Writer out, int sz)
 *                创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
 *           参数:
 *              传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高写入效率
 *              sz:指定缓冲区的大小,不写则默认大小
 *        特有的成员方法:
 *            void newLine()
 */
public class Demo03BufferedWriter {
}
练习
import java.io.*;
import java.util.HashMap;

/**
 *    练习:
 *       对文本内容进行排序
 *       按照1,2,3进行排序
 *    分析
 *       创建一个HashMap集合,将key存放每行的序号1,2,3,value存放文本内容
 */
public class Demo05Text {
    public static void main(String[] args) throws IOException {
        //创建HashMap集合存放键值对
        HashMap<String, String> map = new HashMap<>();
        BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
        //1、创建FileReader对象
        FileReader fr = new FileReader("in.txt");
        //2、创建BufferedReader对象
        BufferedReader br = new BufferedReader(fr);
        //3、以每行读取文本内容
        String line = null;
        while ((line = br.readLine()) != null) {
            //3、以.作为分隔符分割
            String[] arr = line.split("\\.");
            //将内容写入map集合中(key序号是有序的,会自动排序)
            map.put(arr[0], arr[1]);
        }
        //4、遍历集合将内容写入文本中
        for (String key : map.keySet()) {
            String value = map.get(key);
            line = key + "." + value;
            bw.write(line);
            bw.newLine();
        }
        //释放资源
        bw.close();
        br.close();
    }
}

转换流
/**
 *    编码和解码
 *        idea默认使用UTF-8类型编码,
 *        FileReader默认只能读取UTF-8类型编码
 */
public class Demo06 {
}

字符编码与字符集
  • 按照某种规则,将字符存储到计算机称为编码
  • 将存储在计算机中的二进制数按照某种规则解析出来称为解码
  • 编码:字符->字节
  • 解码:字节->字符
  • 注意:编码和解码必须按照同一对应规则
  • 当指定了编码,字符集就自然指定了,所以编码才是最终关心的
    在这里插入图片描述
  • 常用的编码及编码集
    在这里插入图片描述
    在这里插入图片描述
字符转换流

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

  • 字符输入转换流
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 *   java.io.OutputStreamWriter extends Writer
 *         OutputStreamWriter 是字符流流向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节
 *
 *   继承父类的共性成员方法:
 * *  *            void close()
 *  *  *           关闭此输出流并释放与此流有关的所有系统资源。
 *  *  *            void flush()
 *  *  *           刷新此输出流并强制写出所有缓冲的输出字节。
 *  *  *            void write(byte[] b)
 *  *  *           将 b.length 个字节从指定的 byte 数组写入此输出流。
 *  *  *            void write(byte[] b, int off, int len)
 *  *  *           将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
 *  *  *            abstract  void write(int b)
 *  *  *           将指定的字节写入此输出流。
 *    构造方法:
 *       OutputStreamWriter(OutputStream out)
 *           创建使用默认字符编码的 OutputStreamWriter。
 *       OutputStreamWriter(OutputStream out, String charsetName)
 *           创建使用指定字符集的 OutputStreamWriter。
 *    参数:
 *       OutputStream out:字节输出流,可以用来转换之后的字节到文件中
 *       String charsetName:指定编码表的名称,不区分大小写,不指定默认是哟个UTF-8
 *     使用步骤:
 *         1、创建OutputStreamWriter对象,构造方法中指定字节输出流和编码表
 *         2、调用OutputStreamWriter对象的write()方法,把字符转换为字节存储在缓冲区
 *         3、调用OutputStreamWriter对象的flush()方法,把缓冲区数据刷新到文件中
 *         4、释放资源
 */
public class Demo01 {
    public static void main(String[] args) throws IOException {
        write_utf_8();
    }

    /**
     *   使用转换流OutputStreamWriter写UTF-8文件
     */
    public static void write_utf_8() throws IOException {
        FileOutputStream fos = new FileOutputStream("a.txt");
        //OutputStreamWriter osw = new OutputStreamWriter(fos);   //默认UTF-8编码
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        osw.write("你好");
        osw.flush();
        osw.close();
    }
}

  • 字符输出转换流
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 *   java.io.InputStreamReader extends Reader
 *        继承父类共有的成员方法
 *             int read()
 *               读取单个字符。
 *             int read(char[] cbuf, int offset, int length)
 *                将字符读入数组中的某一部分。
 *        构造方法:
 *            InputStreamReader(InputStream in)
 *               创建一个使用默认字符集的 InputStreamReader。
 *            InputStreamReader(InputStream in, String charsetName)
 *               创建使用指定字符集的 InputStreamReader。
 *            参数:
 *               InputStream in:字节输入流,读取文件中保存的字节
 *               String charsetName:指定编码表的名称,不区分大小写,不指定默认是哟个UTF-8
 *         使用步骤:
 *            1、创建InputStreamReader对象,构造方法中指定字节输出流和编码表
 *  *         2、调用InputStreamReader对象的read()方法,把字符转换为字节存储在缓冲区
 *  *         4、释放资源
 *       `  注意事项:
 *             构造方法中的编码表要和文件的编码相同,否则会发生编码乱码现象
 */
public class Demo01 {
    public static void main(String[] args) throws IOException {
        read_utf_8();
    }

    public static void read_utf_8() throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
        InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
        int len = 0;
        while ((len = isr.read()) != -1) {
            System.out.println((char) len);   //这里注意要转换为char类型,否则输出的是一个汉字的码值
        }
        isr.close();
    }
}

转换文件编码
/**
 *    练习:转换文件编码
 *        将GBK文件转换为UTF-8文件类型
 *    思路:
 *        先将GBK格式文件读取出来,然后再哟个UTF-8文件写进去
 */
public class Demo02Test {
    public static void main(String[] args) throws IOException {
        gbkToutf_8();
    }

    public static void gbkToutf_8() throws IOException {
        //创建InputStreamReader对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\b.txt"), "UTF-8");
        //创建OutputStreamWriter对象
        OutputStreamWriter osr = new OutputStreamWriter(new FileOutputStream("b.txt"), "UTF-8");
        //读取GBK文件并以UTF-8行式写进去
        int len = 0;
        while ((len = isr.read()) != -1) {
            osr.write(len);
        }
        isr.close();
        osr.close();
    }
}

序列化和反序列化
序列化
  • 把对象以流的形式写入到文件中保存,叫做写对象,也叫对象的序列化
import java.io.Serializable;

/**
 *    序列化和反序列化都会抛出 NotSerializableException  没有序列化异常
 *       类通过实现 Serializable 接口以启用其序列化功能,来实现此接口的类将无法使用任何序列化或反序列化
 *       Serializable类型接口也称为标记类型接口
 *          要进行序列化和反序列化的类必须实现 Serializable 接口,就会给类添加一个标记
 *          当我们进行序列化和反序列化的时候,就会检测类上是否有这个异常
 *              有:可以序列化和反序列化
 *              没有:则抛出 异常
 *        去市场买肉-》肉上有一个蓝色章(检测合格)-》放心购买-》买回来随意吃
 */
public class Person implements Serializable {
    //定义一个序列号,当执行反序列化操作时,Person类中name和age的值,而反序列化操作输出的还是原值
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

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

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 *   java.io.ObjectOutputStream extends OutputStream
 *        ObjectOutputStream  对象的序列化流
 *        作用:把对象以流的形式写入到文件中保存
 *     构造方法:
 *        ObjectOutputStream(OutputStream out)
 *           创建写入指定 OutputStream 的 ObjectOutputStream。
 *     参数:
 *        OutputStream out:字节输出流
 *      特有的成员方法:
 *        writeObject(Object obj)
 *           将指定的对象写入 ObjectOutputStream。
 *
 *     序列化前提:
 *         类必须实现Serializable接口
 *         必须存在类对象的class文件
 *
 */
public class Demo01ObjectOutputStream {
    public static void main(String[] args) throws IOException {
        //创建ObjectOutputStream对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
        oos.writeObject(new Person("好还有", 18));
        oos.close();
    }
}

反序列化
  • 把文件中保存的对象,以流的方式读取出来,也叫做对象的反序列化
    在这里插入图片描述
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 *    java.io.ObjectInputStream extends InputStream
 *        ObjectInputStream  对象的反序列化流
 *    作用:
 *        把文件中保存的对象,以流的方式读取出来使用
 *    构造方法:
 *        ObjectInputStream(InputStream in)
 *           创建从指定 InputStream 读取的 ObjectInputStream。
 *    特有的成员方法:
 *         Object readObject()
 *           从 ObjectInputStream 读取对象。
 *
 *     static:静态关键字
 *         静态优先于非静态加载到内存中(静态优先于对象加载到内存中)
 *         被static修饰的成员变量不能被序列化,序列化的都是对象
 *     transient:瞬态关键字
 *         被transient修饰的成员变量不能被序列化
 *
 *     若age被static则age一直为0
 *
 */
public class Demo02ObjectInputStream {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
        //从中读取一个对象
        Object o = ois.readObject();
        //释放资源
        ois.close();
        //打印对象
        System.out.println(o);
        if (o instanceof Person) {
            Person person = (Person)o;
            System.out.println(person);
        }
    }
}

序列化冲突异常

在这里插入图片描述

序列化集合
import java.io.*;
import java.util.ArrayList;

/**
 *   序列化集合:
 *      当我们要在一个文件中保存多个对象
 *      可以把多个对象保存到一个集合中
 *      对集合进行序列化和反序列化
 *    分析:
 *       1、定义一个存储Person对象的ArrayList的集合
 *       2、再集合中存储Person对象
 *       3、创建一个序列化流ObjectOutputStream对象
 *       4、调用writeObject()方法,对集合进行序列化
 *       5、创建一个反序列化ObjectInputStream集合
 *       6、调用readObject()方法将读取到的对象保存到集合中
 *       7、把Object类型集合转换为ArrayList类型
 *       8、遍历集合
 *       9、释放资源
 */
public class Demo03 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //创建集合
        ArrayList<Person> list = new ArrayList<>();
        //向集合中添加对象
        list.add(new Person("好还有", 18));
        list.add(new Person("打包", 80));
        list.add(new Person("小狗", 90));
        //创建要对象写的目的地
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c.txt"));
        //对集合进行序列化操作
        oos.writeObject(list);
        //创建一个反序列化操作对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c.txt"));
        //读取对象集合
        Object o = ois.readObject();
        //转换集合类型
        ArrayList<Person> list1 = (ArrayList<Person>)o;
        //遍历集合
        for (Person person : list1) {
            System.out.println(person);
        }
        //释放资源
        oos.close();
        ois.close();
    }
}
打印流
import java.io.FileNotFoundException;
import java.io.PrintStream;

/**
 *     java.io.PrintStream
 *        PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
 *      特点:
 *        与其他输出流不同,PrintStream 永远不会抛出 IOException;
 *        只负责数据的输出,不负责数据的读取
 *      特有的成员方法:
 *        void print(任意类型数据)
 *        void println(任意类型数据并换行)
 *      构造方法:
 *        PrintStream(File file)
 *           创建具有指定文件且不带自动行刷新的新打印流。
 *        PrintStream(OutputStream out)
 *           创建新的打印流。
 *        PrintStream(String fileName)
 *           创建具有指定文件名称且不带自动行刷新的新打印流。
 *       PrintStream extends OutputStream
 *       继承自父类的成员方法:
 *   * *  *            void close()
 *  *  *  *           关闭此输出流并释放与此流有关的所有系统资源。
 *  *  *  *            void flush()
 *  *  *  *           刷新此输出流并强制写出所有缓冲的输出字节。
 *  *  *  *            void write(byte[] b)
 *  *  *  *           将 b.length 个字节从指定的 byte 数组写入此输出流。
 *  *  *  *            void write(byte[] b, int off, int len)
 *  *  *  *           将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
 *  *  *  *            abstract  void write(int b)
 *  *  *  *           将指定的字节写入此输出流。
 *
 *     注意事项:
 *         如果使用继承自父类的成员方法write()方法写数据,那么查看数据的时候会查询编码表:a->97
 *         如果使用自己特有的成员方法print,println方法写数据,写的数据是原样
 */
public class Demo01PrintStream {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream pr = new PrintStream("d.txt");
        //调用父类的方法写入数据
        pr.write(97);
        //调用特有的成员方法写入数据
        pr.println(97);
        pr.close();
    }
}
设置指定目的地的打印流
import java.io.FileNotFoundException;
import java.io.PrintStream;

/**
 *   可以改变输出语句的目的地(打印流语句)
 *       输出语句,默认在控制台输出
 *       使用System.setOut()方法改变输出语句的目的地改为参数中传递打印流的目的地
 *          static void setOut(PrintStream out)
 *            重新分配标准输出流
 */
public class Demo02PrintStream {
    public static void main(String[] args) throws FileNotFoundException {
        System.out.println("我在控制台输出");

        //设置打印流目的地
        PrintStream ps = new PrintStream("e.txt");
        //把输出语句中目的地改变为打印流的目的地
        System.setOut(ps);
        System.out.println("我在打印流目的地中输出");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值