3.4IO流
4.1 File
4.1.1 定义
- 文件和目录路径名的抽象表示。(即该路径可能存在也可能不存在)
 
4.1.2 常用构造器
- File(String pathname):传入一个路径。
 - File(String parent, String child):传入一个父路径和子路径。
 - File(File parent,String child):传入一个父对象和子路径。
 
4.1.3 常用方法
4.1.3.1 文件
- 长度-length() 结合子级文件递归操作
 - 创建-createNewFile():不存在创建成功,反之失败
 - con:操作系统名,不可创建成功
 - 删除-delete():存在删除成功,反之失败
 
4.1.3.2 文件夹
- 创建:
 
- mkdir:父目录必须存在,否则创建失败
 - mkdirs:父目录可以不存在,创建目标文件夹时自动创建父文件夹
 
- 遍历:
 
- list():下级名称
 - listFile():下级对象(判断文件夹内是否含有文件)
 - listRoots():根路径
 
4.1.3.3 文件名、路径名
- getName():获得文件名(结合子级文件递归操作)
 - getPah():获得路径名
 - getAbsolutePath():获得绝对路径名
 - getParent():获得父路径
 - getParentFile():获得父对象
 
4.1.3.4 状态判断
- exists():文件是否存在(结合mkdirs\mkdir)
 - isFile():是否是文件(结合子级文件递归操作)
 - isDirectory:是否是文件夹(结合子级文件递归操作)
 
4.1.4 分隔符
- 路径分隔符
 
- String :pathSeparator
 
- 名称分隔符
 
- String :separator
 
- ->//
 
4.1.5 遍历应用
4.1.6 遍历输出文件夹
    public static void main(String[] args) {
        File file = new File("E:\\Study\\java");
        listFiles(file,1);
    }
    public static void listFiles(File file,int deep) {
        //打印层数
        for (int i = 0; i < deep; i++) {
            System.out.print("-");
        }
        System.out.println(file.getName());
        if (file == null || !file.exists()) {
            return;
        } else if (file.isDirectory()) {
            for (File f : file.listFiles()) {
                listFiles(f,deep+1);
            }
        }
    }

4.1.6 遍历输出文件(过滤器功能)(少用)
    public static void listFile(File file) {
        //创建过滤器规则
        File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                if (pathname.getName().endsWith(".avi") || pathname.isDirectory()) 
                    return true;
                return false;
            }
        });
        if (files != null && files.length > 0) {
            for (File f : files) {
                if (f.isDirectory()) {
                    listFile(f);
                } else {
                    System.out.println("一个avi文件" + f.getAbsolutePath());
                }
            }
        }
    }

4.1.6 相对路径和绝对路径
- 绝对路径:带盘符
 - 相对路径:当前工程下路径
 
4.2 IO介绍
4.2.1 5类3接口
- 文件类:File类
 - 字节流:inputstream,outputstream
 - 字符流:reader,writer
 - 关闭流接口:Closeable
 - 刷新流接口:Flushable
 - 序列化接口:Serializable
 
4.2.2 流分类
- 输入流:inputstream,reader
 - 输出流:outputstream,writer
 - 节点流:可直接从数据源或目的地处理数据
 - 处理流:其他流封装,为了提高效率
 
4.2.3 字节流
4.2.3.1 输出流
    public static void main(String[] args) throws IOException {
        File file = new File("e:\\a.txt");
        writeByte(file);
        writeByteArrays(file);
    }
    /**
     * 写一个字节
     * @param file
     * @throws IOException
     */
    public static void writeByte(File file) throws IOException {
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(65);
        fos.close();
        System.out.println("已输出");
    }
    /**
     * 写一组字节
     * @param file
     * @throws IOException
     */
    public static void writeByteArrays(File file) throws IOException {
        FileOutputStream fos = new FileOutputStream(file);
        //方式一
        byte[] bytes = {65, 66, 67};
        //方式二
        byte[] bytes1="abcd".getBytes();
        fos.write(bytes);
        fos.write(bytes1);
        fos.write(bytes1, 1, 2);//开始下标和写出长度
        fos.close();
        System.out.println("已输出");
    }

4.2.3.2 关于FileOutputStream第二个参数append
- 如果是同一个流在程序一次运行期间写不同文件,可自动追加内容
 - 如上图中的方式二写了两个内容,且内容不被覆盖。
 - 如果修改内容,且append为false,则程序第二次覆盖掉原本的内容。
 - 如果是不同流
 - append为true:追加内容
 - append为false(默认):覆盖内容
 
4.2.3.3 输入流
    public static void main(String[] args) throws IOException {
        File file = new File("e:\\a.txt");
        readByte(file);
        readByteArrays(file);
    }
    /**
     * 读一个字节
     * @param file
     * @throws IOException
     */
    public static void readByte(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        while (true) {
            byte b=(byte)fis.read();
            if (b == -1) {//没有数据则读取-1
                break;
            }
            System.out.print((char)b+" ");
        }
        System.out.println();
        fis.close();
    }
    /**
     * 读一组字节
     * @param file
     * @throws IOException
     */
    public static void readByteArrays(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        byte[] bytes = new byte[10];//每次读取10个字节
//        fis.read(bytes);
//        System.out.println(new String(bytes));
//        fis.read(bytes);
//        System.out.println(new String(bytes));
//        fis.read(bytes);
//        System.out.println(new String(bytes));
        int len = -1;
        while ((len=fis.read(bytes))!=-1) {
            System.out.println(new String(bytes,0,len));
        }
        fis.close();
    }

4.2.3.3.1 注意事项
- 输入流读取时要控制长度,否则结果出错。
 
4.2.4 编码解码
4.2.4.1 定义
- 编码:字符到字节
 - 解码:字节到字符
 
4.2.4.2 产生背景
- 计算机只存储二进制位,为了方便人们阅读,出现汉字编码,不同国家有不同的编码规则。
 
4.2.4.3 常见格式
- 简体中文编码-国标码:GBK,GB2312,GB18030
 - ASCII码:有一个ASCII码参照表,有256个符号,每种编码格式都兼容ASCII码,所以英文不乱码
 - 可变长度编码-Unicode码:UTF-8,UTF-16..
 
4.2.4.4 乱码原因
- 字节数不够:通过字节流逐个读取字符集,字符集中包含中文
 
- 表现:汉字显示不全
 
- 字符集不统一:源文件和转换后的文件编码解码格式需统一
 
- 表现:不能正确显示汉字
 
4.2.5 字符流
4.2.5.1 输出流
4.2.5.1.1 应用
    public static void main(String[] args) throws IOException {
        File file = new File("e:b.txt");
        fileByte(file);
        fileString(file);
    }
    /**
     * 输出一个字符
     * @param file
     * @throws IOException
     */
    public static void fileByte(File file) throws IOException {
        FileWriter fw = new FileWriter(file);
        fw.write('c');
        fw.close();
    }
    public static void fileString(File file) throws IOException {
        FileWriter fw = new FileWriter(file,true);//是否在已有内容后面写新内容
        fw.write("白日依山尽");
        fw.append("黄河入海流");//追加要输出的新内容
        fw.close();
    }

4.2.5.1.2 flush
- 字符输出流底层原理也是基于字节输出流实现的,一个字符如果占用三个字节,则连续读取三个字节后才输出一个字符,这些字符存放在缓冲区,需要通过flush方法将缓冲区刷新一遍,内容才能正常输出。当调用close方法时也自动调用了一遍flush方法,若两个方法都不调用,则不显示内容。
 
4.2.5.2 输入流
    public static void main(String[] args) throws IOException {
        File file = new File("e:b.txt");
        fileByte(file);
        fileString(file);
    }
    /**
     * 读取一个字符
     * @param file
     * @throws IOException
     */
    public static void fileByte(File file) throws IOException {
        FileReader fr = new FileReader(file);
        while (true) {
            int c = fr.read();
            if (c == -1) {
                break;
            }
            System.out.println((char)c);
        }
    }
    /**
     * 读取一组字符
     * @param file
     */
    public static void fileString(File file) throws IOException {
        FileReader fr = new FileReader(file);
        //char数组默认存储0,若不限制长度,则内容输出完毕后,会继续输出剩余位置的0
        char[] chars = new char[100];
        int len=-1;
        while ((len = fr.read(chars)) != -1) {
            System.out.println(new String(chars,0,len));
        }
    }

4.2.6 输入时不限制长度区别
- 字节流:待输出内容覆盖上一组部分内容后一起输出
 - 字符流:连同剩余空格一起输出
 
4.2.7 转换流(字节流-->字符流)
- 输出:OutputStreamWriter
 - 输入:InputStreamReadre
 
    OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("e://a.txt"));
4.2.8 字符打印流
- PrintStream
 - PrintWriter
 
4.2.8.1 区别
- PrintWriter需刷新管道
 
4.2.8.2 作用
- 字节流转换成字符流输出用PrintWriter而不是OutputStreamWriter
 
4.2.8.3 应用
    PrintWriter pw=new PrintWriter(new FileOutputStream("e://a.txt"));
4.2.9 缓存流
4.2.9.1 读取流BufferedReader
- 作用:将字符输入流转换为带有缓存,可以一次读取一行的缓存字符读取流
 
    BufferedReader br=new BufferedReader(new FileReader("e://a.txt"));
    String text=br.readLine();
4.2.10 收集异常日志
    try{
        String s=null
        s.toString();
    }catch(Exception e){
        //打印异常时间
        PrintWriter pw=new PrintWriter("e://bug.txt");
        String text=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        pw.println(text);
        e.printStackTrace(pw);
        pw.close();
    }
4.2.11 Properties
4.2.11.1 概念
- Properties可以保存到流中或从流中加载。属性列表中的每个键及其对应的值都是一个字符串。
 
4.2.11.2 注意
- 因为Properties继承自Hashtable,所以put和putAll方法可以应用于Properties对象。 强烈建议不要使用它们,因为它们允许调用者插入其键或值不是Strings.应该使用setProperty方法。 如果在包含非String键或值的“受损”Properties对象上调用store或save方法,则调用将失败。
 
4.2.11.3 应用
    public static void main(String[] args) throws IOException {
        Properties ppt=new Properties();
        /*ppt.put("1", "金苹果");
        ppt.put("2", "银苹果");*/
        ppt.setProperty("1", "金苹果");
        ppt.setProperty("2", "银苹果");
        //输出流存储文件
        FileWriter fw = new FileWriter("e://apple.properties");
        ppt.store(fw, "苹果种植");//comment:注释
        fw.close();
        //输入流读取文件
        FileReader fr = new FileReader("e://apple.properties");
        ppt.load(fr);
        System.out.println(ppt.getProperty("1"));
        System.out.println(ppt.getProperty("2"));
        fr.close();
    }
4.2.12 序列化与反序列化
4.2.12.1 提出背景
- 为了实现网络传输和本地存储
 
4.2.12.2 概念
- 序列化:把java对象转换为字节序列的过程,即将对象存储到文件中
 - 反序列化:把字节序列转换为java对象的过程,即从文件中读取对象
 
4.2.12.3 应用
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //序列化
        //创建Book对象
        Book b = new Book("金苹果", "很好吃");
        //创建输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e://book.txt"));
        //写入数据
        oos.writeObject(b);
        //关闭流
        oos.close();
        //反序列化
        //创建输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e://book.txt"));
        //读取数据
        Book o=(Book)ois.readObject();
        System.out.println(o.getInfo());
        //关闭流
        ois.close();
    }
    static class Book implements Serializable {
        private String name;
        private String info;
        public Book(String name, String info) {
            this.name = name;
            this.info = info;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getInfo() {
            return info;
        }
        public void setInfo(String info) {
            this.info = info;
        }
    }

4.2.12.4 注意
- 要写入的对象必须实现Serializable接口,该接口是标记接口,不含抽象方法
 
4.2.12.5 部分属性序列化
- transient修饰符
 - static修饰符
 
- 原理:static修饰的属性为静态属性,不参与序列化,反序列化后的对象还是原本的内存空间
 
- 序列化后可通过set方法测试该属性是否参与序列化
 
- 默认方法writeObject,readObject
 
- 原理:java调用ObjectOutputStream类检查其是否有 私有的、无返回值的 writeObject方法和readObject方法,如果有,则会委托该方法进行对象序列化和反序列化。这两个方法来自于Serialiable接口,所以序列化的对象需要实现该接口。
 - 注意:
 
* 添加的两个方法必须是 private void ,否则不生效
* 序列化与反序列化的顺序必须一致
- Externaliable接口
 
- 原理:继承Serialiable接口,通过重写writeExternal和readExternal
 
4.2.12.6 Serializable和Externalizale区别
4.2.13 try-catch-resources
4.2.13.1 异常处理格式
- JDK1.7之前,需通过finally关闭
 
        //JDK1.7前
        FileReader fr=null;
        try {
            fr = new FileReader("e://b.txt");
            int read = fr.read();
            System.out.println((char)read);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
- JDK1.7优化后,在try后创建流即可调用close方法
 
        //JDK1.7优化后
        try(FileReader fr2 = new FileReader("e://b.txt")){
            int read = fr2.read();
            System.out.println((char)read);
        } catch (Exception e) {
            e.printStackTrace();
        }
- 若调用的流不是此时创建,而是已创建的,则无法通过该格式调用,所以引入了新的格式
 - JDK9,不同的流只需分号隔开即可,且不用在try后创建
 
        //JDK9
        FileReader fr3 = new FileReader("e://b.txt");
        PrintWriter pw = new PrintWriter("e://b.txt");
        try(fr3;pw){
            int read = fr3.read();
            System.out.println((char)read);
        } catch (Exception e) {
            e.printStackTrace();
        }

4.2.13.2 注意
- try后若传入的对象,都必须实现Closeable接口,该对象需实现close()方法
 
    welcome~the interesting soul



                
            
        
浙公网安备 33010602011771号