美文网首页
IO流对象

IO流对象

作者: 上炼致知 | 来源:发表于2020-05-25 08:42 被阅读0次

    File

    IO概述

    要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、u盘等)上;

    • Output:把内存中的数据存储到持久化设备上,这个动作称为输出(写)Output操作
    • Input:把持久化设备上的数据读取到内存中,这个动作,称为输入(读)Input操作

    把以上这种输入和输出操作动作称为IO操作;

    File类概述和作用

    File类时文件和目录路径名的抽象表示形式

    Java中把文件或者目录(文件夹)都封装成File对象

    要去操作硬盘上的文件或者文件夹,只要找到File这个类即可;

    File类的静态成员变量

    • pathSeparator 与系统有关的路径分隔符;为了方便被表示为一个字符串;

    • separator 与系统有关的默认名称分隔符;为了方便被表示为一个字符串;

      System.out.println(File.pathSeparator);//:(Mac)
      System.out.println(File.separator);// /(Mac)
      

    File类的构造函数

    • File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建一个新File实例;

      /**
       * 将路径封装File类型对象
       * 传递路径名,可以写到文件夹,也可以写到文件
       */
      String pathName = "/Users/syjsuccess/Desktop/hello1";//windows中斜杠为反斜杠,需要标示为\\,如e:\\java_code\\day22e\\hello1.java
      File file1 = new File(pathName);
      System.out.println(file1);// /Users/syjsuccess/Desktop/hello1
      
    • File(String parent, String child) 根据parent路径名字符串和child路径名字符串创建一个新File实例;

      /**
       * 传递字符串父路径,字符串子路径
       * 好处:单独操作父路径和子路径
       */
      File file2 = new File("/Users/syjsuccess/Desktop", "hello2");
      System.out.println(file2);// /Users/syjsuccess/Desktop/hello2
      
    • File(File parent, String child) 根据parent抽象路径名和child路径名字符串创建一个新File实例;

      /**
       * 传递File类型父路径,字符串路径
       * 好处:父路径是File类型,父路径是可以直接调用File类方法
       */
      File parent = new File("/Users/syjsuccess/Desktop");
      File file3 = new File(parent, "hello3");
      System.out.println(file3);// /Users/syjsuccess/Desktop/hello3
      

    相对路径和绝对路径

    绝对路径:绝对路径是一个固定的路径,从盘符开始;具有唯一性

    相对路径:相对路径相对于某个位置;表示路径之间的关系;

    File类的获取

    • String getAbsolutePath() 返回此抽象路径名的绝对路径字符串;

    • File getAbsoluteFile() 获取绝对路径,返回File对象;

      /**
       * 获取绝对路径
       * 在idea环境中,写的是一个相对路径,获取到绝对位置工程根目录
       */
      File file = new File("src");
      File absolute = file.getAbsoluteFile();
      System.out.println(absolute);// /Users/syjsuccess/Documents/Java/learning/src
      String absoluteStr = file.getAbsolutePath();
      System.out.println(absoluteStr);// /Users/syjsuccess/Documents/Java/learning/src
      
    • String getParent() 获取父路径,返回String对象;

    • File getParentFile() 获取父路径,返回File对象;

      /**
       * 获取父路径
       */
      File file = new File("/Users/syjsuccess/Downloads/vue.js");
      File parent = file.getParentFile();
      System.out.println(parent);// /Users/syjsuccess/Downloads
      String parentStr = file.getParent();
      System.out.println(parentStr);// /Users/syjsuccess/Downloads
      
    • String getPath() 将此抽象路径名转换为一个路径名字符串;

      File file = new File("/Users/syjsuccess/Downloads/vue.js");
      String path = file.getPath();
      System.out.println(path);// /Users/syjsuccess/Downloads/vue.js
      
    • String getName() 返回由此抽象路径名表示的文件或目录的名称;

      /**
       * 返回路径中表示的文件或者文件夹的名字
       * 获取路径中的最后部分的名字
       */
      File file = new File("/Users/syjsuccess/Downloads/vue.js");
      String name = file.getName();
      System.out.println(name);// vue.js
      
    • long length() 返回由此抽象路径名表示的文件的长度;

      /**
       * 返回路径中表示的文件的字节数
       */
      File file = new File("/Users/syjsuccess/Downloads/vue.js");
      long length = file.length();
      System.out.println(length); //341462
      

    File类判断功能

    • boolean exists() 判断File构造方法中封装路径是否存在

      /**
       * 判断File构造方法中封装路径是否存在
       * 存在返回true,不存在返回false
       */
      File file = new File("/Users/syjsuccess/Downloads/vue.js");
      boolean flag = file.exists();
      System.out.println(flag);//true
      
    • boolean idDirectory() 判断File构造方法中封装的路径是不是文件夹

    • boolean isFile() 判断File构造方法中封装的路径是不是文件

      /**
       * boolean isDirectory() 判断File构造方法中封装的路径是不是文件夹
       * boolean isFilr() 判断File构造方法中封装的路径是不是文件
       */
      File file1 = new File("/Users/syjsuccess/Downloads/vue.js");
      if (file1.exists()) {
          boolean flag1 = file1.isDirectory();
          System.out.println(flag1);// false
          boolean isFile1 = file1.isFile();//true
          System.out.println(isFile1);
      }
      File file2 = new File("/Users/syjsuccess/Downloads");
      if (file2.exists()) {
          boolean flag2 = file2.isDirectory();
          System.out.println(flag2);// true
          boolean isFile2 = file2.isFile();//false
          System.out.println(isFile2);
      }
      

    File类创建文件功能

    • public boolean createNewFile() 创建文件,如果已经存在,就不创建了

      /**
       * 如果文件已经存在则不再创建
       */
      File file = new File("/Users/syjsuccess/Desktop/ceshi.txt");
      boolean flag = file.createNewFile();
      System.out.println(flag);
      

    File类创建文件夹功能

    • public boolean mkdir() 创建文件夹,如果存在这样的文件夹,就不创建了;

    • public boolean mkdirs() 创建文件夹,如果父文件夹不存在,会自动创建出来;

    • 以上两者区别:mkdir()是创建子目录,mkdirs()是创建多级目录;一般用mkdirs()就行

      /**
       * 如果文件夹已经存在就不再创建
       */
      File file = new File("/Users/syjsuccess/Desktop/ceshi");
      boolean flag = file.mkdirs();
      System.out.println(flag);
      

    File类删除功能

    • public boolean delete() 删除文件或者文件夹;

      /**
       * 删除成功返回true,删除失败返回false
       * 该删除方法不走回收站,直接从硬盘中删除;删除有风险,运行需谨慎
       */
      File file = new File("/Users/syjsuccess/Desktop/ceshi.txt");
      boolean flag = file.delete();
      System.out.println(flag);
      

    File类list获取功能

    • String[] list() 获取到File构造方法中封装的路径中的文件和文件夹名(遍历一个目录);

      /**
       * 返回只有名字
       */
      File file = new File("/Users/syjsuccess/Desktop");
      String[] fileStrArr = file.list();
      for (String str : fileStrArr) {
            System.out.println(str);
      }
      /**
       * ceshi
       * IOTest
       * .DS_Store
       * .localized
       * 笔记
       */
      
    • File[] listFiles() 获取到File构造方法中封装的路径中的文件和文件夹名(遍历一个目录);

      /**
       * 返回的是目录或者文件的全路径
       */
      File file = new File("/Users/syjsuccess/Desktop");
      File[] fileArr = file.listFiles();
      for (File f : fileArr) {
        System.out.println(f);
      }
      /**
       * /Users/syjsuccess/Desktop/ceshi
       * /Users/syjsuccess/Desktop/IOTest
       * /Users/syjsuccess/Desktop/.DS_Store
       * /Users/syjsuccess/Desktop/.localized
       * /Users/syjsuccess/Desktop/笔记
       */
      
    • static File[] listRoots() 列出可用的文件系统根;

      File[] fileArr = File.listRoots();
      for (File file : fileArr) {
            System.out.println(file);
      }
      

    文件过滤器

    通过listFile()方法,可以获取到一个目录下的所有文件和文件夹,如果想对其进行过滤,比如只想要一个目录下的指定扩展名的文件,可以先把一个目录下的所有文件和文件夹获取到,然后遍历当前获取到的所有内容,遍历过程中进行筛选;

    • File[] listFiles(FilenameFilter filter) 返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和文件夹;

      public class MyFilenameFilter implements FilenameFilter {
          /**
           * dir - 被找到的文件所在的目录。
           * name - 文件的名称。
           */
          @Override
          public boolean accept(File dir, String name) {
              return name.endsWith(".txt");
          }
      }
      public class Test {
          public static void main(String[] args) throws IOException {
              //创建file对象
              File file = new File("/Users/syjsuccess/Desktop/ceshi");
              //获取指定扩展名的文件
              File[] files = file.listFiles(new MyFilenameFilter());
              for (File f : files) {
                  System.out.println(f);
              }
          }
      }
      /**
       * /Users/syjsuccess/Desktop/ceshi/2.txt
       * /Users/syjsuccess/Desktop/ceshi/1.txt
       */
      
    • File[] listFiles(FileFilter filter) 返回抽象路径名数组,这些路径名表示此抽象路径表示的目录中满足指定过滤器的文件和文件夹;

      public class MyFileFilter implements FileFilter {
          /**
           * pathname - 要测试的抽象路径名
           */
          @Override
          public boolean accept(File pathname) {
              return pathname.isDirectory();
          }
      }
      public class Test {
          public static void main(String[] args) throws IOException {
              //创建file对象
              File file = new File("/Users/syjsuccess/Desktop/ceshi");
              //获取指定目录下的文件夹
              File[] files = file.listFiles(new MyFileFilter());
              for (File f : files) {
                  System.out.println(f);
              }
          }
      }
      /**
       * /Users/syjsuccess/Desktop/ceshi/1
       * /Users/syjsuccess/Desktop/ceshi/2
       */
      
    • FilenameFilter和FileFilter使用区别:当需要过滤文件名称时就可以使用FilenameFilter这个过滤器;当想对当前文件或文件夹进行过滤就可以使用FileFilter,比如需要当前目录下的所有文件夹就可以使用FileFilter过滤器

    递归

    递归概述

    递归指在当前方法内调用自己的这种现象

    递归分为两种,直接递归和间接递归;

    直接递归称为方法自身调用自己;间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法;

    /**
     * 递归打印子目录中的所有文件
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        File file = new File("/Users/syjsuccess/Desktop/ceshi");
        getAllFile(file);
    }
    public static void getAllFile(File file) {
        File[] listFile = file.listFiles(new MyFilenameFilter());
        for (File fi : listFile) {
                if (fi.isFile()) {
                    System.out.println(fi.getName());
                } else if (fi.isDirectory()) {
                    getAllFile(fi);
                }
        }
    }
    public class MyFilenameFilter implements FilenameFilter {
        @Override
        public boolean accept(File dir, String name) {
            return !name.endsWith(".DS_Store");
        }
    }
    

    递归适用于:方法中运算的主体不变,但是运行的时候,参与运行的方法参数会变化

    注意:递归一定要有出口,必须可以让程序停下;递归次数不能过多;构造方法禁止用递归

    示例:斐波那契数列

    public class Test {
        public static void main(String[] args) throws IllegaInputException {
            int num = 12;
            fibonacciStr(num);
        }
        public static void fibonacciStr(int num) throws IllegaInputException {
            if (num <= 0) {
                throw new IllegaInputException("不能输入小于等于0的整数");
            }
            int[] arr = new int[num];
            for (int i = 0; i < num; i++) {
                arr[i] = Fib(i + 1);
            }
            System.out.println(Arrays.toString(arr));//[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
        }
        public static int Fib(int num) {
    
            while (num > 2) {
                return Fib(num - 1) + Fib(num - 2);
            }
            return 1;
        }
    }
    public class IllegaInputException extends Exception {
        public IllegaInputException() {
            super();
        }
        public IllegaInputException(String str) {
            super(str);
        }
    }
    

    字节流

    输入和输出

    Output:把内存中的数据存储到持久化设备上,这个动作称为输出(写),Output操作;(程序到文件)

    Input:把持久化设备上的数据存储到内存中,这个动作称为输入(读),Input操作;(文件到程序)

    IO操作:上面的这种输入和输出的动作称为IO操作;

    IO流

    IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式来进行操作;Java用于操作流的类都在IO包中;

    流按流向分为:输入流输出流

    流按操作类型分为:字节流字符流

    字节流 字符流
    字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的; 字符流只能操作纯字符数据,比较方便
    父类(抽象):InputStreamOutputStream 父类(抽象):ReaderWriter

    字节输出流OutputStream

    OutputStream是抽象类,是表示输出字节流的所有类的超类,操作的数据都是字节,定义了输出字节流的几本共性功能方法;

    • void write(byte[] b) 将b.length个字节从指定的btye数组中写入此输出流;
    • void write(byte[] b, int off, in len) 将指定byte数组中从偏移量off开始的len个字节写入此输出流;
    • abstract write(int b) 将指定的字节写入此输出流;
    • void flush() 刷新此输出流,并强制写出所有缓冲的输出字节;
    • void close() 关闭此输出流,并释放与此流相关的所有系统资源;

    字节输出流FileOutputStream类些字节

    OutputStream有很多子类,其中子类FileOutputStream可以用来写入数据到文件;

    FileOutputStream类,即文件输出流,用于将数据写入File的输出流

    FileOutputStream的构造方法的作用:绑定输出的输出目的,即绑定数目的

    • FileOutputStream(File file) 创建一个向指定File对象表示的文件中写入数据的文件输出流;

    • FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流;

    • 流对象的构造方法可以创建文件,如果文件已经存在,则直接覆盖掉

      流对象使用步骤:
      1. 创建流子类的对象,绑定数据目的;
      2. 调用流对象的写方法write;
      3. close释放资源;
      
      //创建流子类对象,绑定数据目的
      FileOutputStream fos = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1.txt");
      //流对象的write方法写数据,写1个字节
      fos.write(97);
      //关闭资源
      fos.close();
      
      //创建存储数据的文件
      File file = new File("/Users/syjsuccess/Desktop/ceshi/output.txt");
      //创建一个用于操作文件的字节输出流对象,一创建就必须明确数据存储目的地
      FileOutputStream fos = new FileOutputStream(file);
      byte[] bytes = "Hello, World!!!".getBytes();
      //调用父类中的write方法
      fos.write(bytes);
      //关闭流资源
      fos.close();
      

    文件的续写和换行符号

    直接new FileOutputStream(file)这样创建对象写入数据,会覆盖原有的文件,可以使用以下两个构造方法,如果第二个参数为true,则会在文件的末尾续写;

    • FileOutputStream(File file, boolean append) 创建一个向指定File对象表示的文件中写入数据的文件输出流;

    • FileOutputStream(String name, boolean append) 创建一个向具有指定name的文件中写入数据的输出文件流;

    • 换行符,不同系统不同处理方式;可以写在上一行的末尾,也可以写在下一行的开头;

      系统 换行符
      windows \r\n
      \r回车,回到当前行的行首
      \n换行,换到当前行的下一行,而不会到行首
      unix \n
      每行结尾只有换行,即\n
      mac \r
      每行结尾是回车,即\r
      File file = new File("/Users/syjsuccess/Desktop/ceshi/output.txt");
      FileOutputStream fos = new FileOutputStream(file, true);
      fos.write("\rLearn Java!\r".getBytes());
      fos.write("Learn IO!".getBytes());
      fos.close();
      

    IO异常的处理

    IO流的异常处理:try catch finall

    public static void main(String[] args) throws IOException {
        File file = new File("/Users/syjsuccess/Desktop/ceshi/output.txt");
        //定义FileOutputStream的引用
        FileOutputStream fos = null;
        try {
            //创建FileOutputStream对象
            fos = new FileOutputStream(file);
            //写出数据
            fos.write("abcde".getBytes());
        } catch (IOException e) {
            System.out.println(e.toString() + "------");
        } finally {
            //一定要判断流对象是否为null,只有不为null时,才可以关闭资源
            if (fos != null) {
                try {
                    fos.close();
                }catch (IOException e) {
                    throw new RuntimeException(e.toString());
                }
            }
        }
    }
    

    字节输入流InputStream

    如何把持久化设备中的数据读到内存中,可以通过InputStream可以实现。InputStream是抽象类,是表示字节输入流的所有类的超类,定义了字节输入流的基本共性功能方法

    • abstract int read() 从输入流中读取数据的下一个字节;没有字节返回-1;
    • int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储到缓冲区数组b中;读入缓冲区的字节总数如果因为已经到达文件末尾而没有更多的数据,则返回-1
    • int read(byte[] b, int off, int len) 将输入流中最多len个数据字节读入byte数组;
    • void close() 关闭此输入流,并释放与该流关联的所有系统资源了;

    FileInputStream类

    InputStream有很多子类,其中子类FileInputStream可以用来读取文件内容;FileInputStream从文件系统中的某个文件中获得输入字节;

    • FileInputStream(File file) 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定;

    • FileInputStream(String name) 通过打开一个到时间文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径名name指定;

      • 字节输入流FileInputStream读取字节:int read() 方法执行一次,就会自动读取下一个字节,返回值返回的是读取到的字节,读取到结尾返回-1

        /**
         * 输入流读取文件的步骤
         * 1. 创建字节输入流的子类对象
         * 2. 调用读取方法read读取
         * 3. 关闭资源
         */
        //创建一个字节输入流对象,必须明确数据源,其实就是创建字节读取流和数据源相关联
        FileInputStream fis = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/output.txt");
        //读取一个字节,调用方法read,返回int
        //使用循环方式,读取文件,循环结束的条件,read()方法返回-1
        int len = 0;
        while ((len = fis.read()) != -1 ) {
            System.out.print((char) len);
        }
        fis.close();
        /**
         * Learn IO!
         * Learn Java!
         * Learn IO!
         * Learn Java!
         * Learn IO!
         */
        
      • 字节输入流FileInputStream读取字节数组:

        //创建一个字节输入流对象,必须明确数据源,其实就是创建字节读取流和数据源相关联
        FileInputStream fis = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/output.txt");
        //创建字节数组;长度可以定义成1024的整数倍
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = fis.read(buf)) != -1) {
            System.out.println(new String(buf, 0, len));
        }
        fis.close();
        

    字节输入流FileInputStream读取字节数组的实现原理

    读取数组的原理.JPG

    字节流复制文件---读取单个字节

    //定义两个流的对象
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        //建立两个流的对象,绑定数据源和数据目的
        fis = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/output.txt");
        fos = new FileOutputStream("/Users/syjsuccess/Desktop/output.txt");
        //字节输入流,读取1个字节,输出流写1个字节
        int len = 0;
        while ((len = fis.read()) != -1) {
            fos.write(len);
        }
    } catch (IOException e) {
        System.out.println(e);
        throw new RuntimeException("文件复制失败");
    } finally {
        try {
            if (fos != null) {
                fos.close();
            }
        } catch (IOException ex) {
            throw new RuntimeException("释放资源失败");
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                } 
            } catch (IOException e) {
                throw new RuntimeException("释放资源失败");
            }
        }
    }
    

    上述代码复制文件有个问题:每次都从源文件读取一个,然后再写到指定文件,接着再读取一个字节,然后再写,这要效率极低;因此需要采用以下数组缓冲提高效率;

    字节流复制文件---读取字节数组

    long s = System.currentTimeMillis();
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        fis = new FileInputStream("/Users/syjsuccess/Documents/syj/mine/硕士阶段/硕士毕业照/_MG_2346.jpg");
        fos = new FileOutputStream("/Users/syjsuccess/Desktop/_MG_2346.jpg");
        //定义字节数组,缓冲
        byte[] bytes = new byte[1024 * 10];
        //读取数组,写入数组
        int len = 0;
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
        }
    } catch (IOException e) {
        System.out.println(e);
        throw new RuntimeException("文件复制失败");
    } finally {
        try {
            if (fos != null) {
              fos.close();
            }
        } catch (IOException io) {
            throw new RuntimeException("释放资源失败");
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException io) {
                throw new RuntimeException("释放资源失败");
            }
        }
    }
    

    编码表

    分类 表示
    ASCII 一个字节中的7位就可以表示,对应的字节都是正数;0xxxxxxx
    GBK 目前最常用的中文码表,2万的中文和符号;用两个字节表示两个字节第一个是负数,第二个可能是正数
    GB18030 最新的中文码表,目前还没正式使用;
    unicode 国际标准码表;无论是什么文字,都用两个自己存储
    utf-8 基于unicode,一个字节就可以存储的数据就不用两个字节;更加标准化,在每个字节头加入了编码信息;
    文字--->(数字):编码;  "abc".getBytes()        byte[]
    (数字)---文字:解码;       byte[] bytes = {97, 98, 99}   new String(bytes)
    

    字符输出流Writer

    字符输出流写文本FileWrite类

    • void write(int c) 写入单个字符;
    • void write(String str) 写入字符串;
    • void write(String str, int off, int len) 写入字符串的某部分;
    • void write(char[] cbuf) 写入字符数组;
    • abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分;
    //构造方法,写入的数据目的
    FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/output.txt");
    //写一个字符
    fw.write(100);
    fw.flush();
    
    //写一个字符数组
    char[] c = {'a', 'b', 'c', 'd', 'e'};
    fw.write(c);
    fw.flush();
    
    //写入字符数组的一部分
    fw.write(c, 2, 2);
    fw.flush();
    
    //写如字符串
    fw.write("hello");
    fw.flush();
    
    fw.close();
    

    字符输入流Reader

    字符输入流读取文本FileReader类

    • int read() 读取单个字符;
    • int read(char[] cbuf) 将字符读入数组;
    • abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分;
    //构造方法,绑定数据源
    FileReader fr = new FileReader("/Users/syjsuccess/Desktop/ceshi/output.txt");
    char[] ch = new char[1024];
    int len = 0;
    while ((len = fr.read(ch)) != -1) {
        System.out.println(new String(ch, 0, len));
    }
    
    fr.close();
    

    flush方法和close方法的区别

    flush方法 close方法
    用来刷新缓冲区的,刷新后可以再次写出,只有字符流才需要刷新 用来关闭流释放资源的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭之前刷新缓冲区,关闭后不能再写出;

    字符流复制文本文件

    FileReader fr = null;
    FileWriter fw = null;
    try {
        fr = new FileReader("/Users/syjsuccess/Desktop/ceshi/output.txt");
        fw = new FileWriter("/Users/syjsuccess/Desktop/output.txt");
        char[] cbuf = new char[1024 * 10];
        int len = 0;
        while ((len = fr.read(cbuf)) != -1) {
            fw.write(cbuf, 0, len);
            fw.flush();
        }
    } catch (IOException e) {
        System.out.println(e);
        throw new RuntimeException("复制失败");
    } finally {
        try {
            if (fw != null) {
                fw.close();
            }
        } catch (IOException io) {
            throw new RuntimeException("释放资源失败");
        } finally {
            try {
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException io) {
                throw new RuntimeException("释放资源失败");
            }
        }
    }
    

    转换流

    转换流.JPG

    OutputStreamWriter类写文本文件

    OutputStreamWriter是字符流通向字节流的桥梁;可使用指定的字符编码表,将要写入流中的字符编码成字节;它的作用就是:将字符串按照指定的编码表转成字节,再使用字节流将这些字节写出去

    当调用OutputStreamWriter流对象的write方法时,会拿着字符到指定的码表中去进行查询,把查到的字符编码值转换成字节数存放到OutputStreamWriter缓冲区中,然后再调用刷新功能、或者关闭流、或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中;

    /*
     * 转换流对象OutputStreamWriter写文本
     * 采用UTF-8编码表写入
     */
    //创建字节输出流,绑定文件
    FileOutputStream fileOutputStream = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1/utf.txt");
    //创建转换对象,构造方法,保证字节输出流,并指定编码表是utf-8
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
    outputStreamWriter.write("你好");
    outputStreamWriter.close();
    
    /*
     * 转换流对象 OutputStreamWriter写文本
     * 文本采用GBK的形式写入
     */
    //创建字节输出流,绑定文件
    FileOutputStream fileOutputStream = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1/gbk.txt");
    //创建转换对象,构造方法,保证字节输出流,使用gbk编码表
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
    outputStreamWriter.write("你好");
    outputStreamWriter.close();
    

    InputStreamReader类读取文本文件

    InputStreamReader是字节流通向字符流的桥梁,它使用指定的字符编码表读取字节并将其解码问字符;

    /*
     *  转换流,InputSteamReader读取文本
     *  采用系统默认编码表,读取GBK文件
     */
    //创建字节输入流,传递文本文件
    FileInputStream fileInputStream = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/1/gbk.txt");
    //创建转换流对象,构造方法中,包装字节输入流,同时写编码表名
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");
    char[] ch = new char[1024];
    int len = inputStreamReader.read(ch);
    System.out.println(new String(ch, 0, len));//你好
    inputStreamReader.close();
    
    
    /*
     *  转换流,InputSteamReader读取文本
     *  采用UTF-8编码表,读取文件utf
     */
    //创建字节输入流,传递文本文件
    FileInputStream fileInputStream = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/1/utf.txt");
    //创建转换流对象,构造方法中,包装字节输入流,同时写编码表名
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
    char[] ch = new char[1024];
    int len = inputStreamReader.read(ch);
    System.out.println(new String(ch, 0, len));//你好
    inputStreamReader.close();
    
    

    转换流和它的子类区别

    继承关系:

    Writer
        |-- OutputStreamWriter
                            |-- FileWriter
    
    Reader
        |-- InputStreamReader
                            |-- FileReader
    
    OutputStreamWriter和InputStreamReader FileWriter和FileReader
    是字符和字节的桥梁;也可称之为字符转换流;转换原理:字节流+编码表 作为子类,仅作为操作字符文件的便捷类存在,当操作的字符文件使用的是默认编码表时可以不用父类
    /*
     * 以下三行代码作用一样,第三句最简便
     */
    InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//使用默认字符集
    InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "gbk");//指定gbk字符集
    FileReader fr = new FileReader("a.txt");
    

    一旦要指定其他编码时,就不能使用子类,必须使用字符转换流;

    字节--->字符 字符--->字节
    看不懂的--->看得懂的 看得懂的--->看不懂的

    缓冲流

    缓冲流概述:可提高IO流得读写速度分为字节缓冲流与字符缓冲流

    字节缓冲流

    • 写入数据到流中,字节缓冲输出流BufferedOutputStream;
    • 读取流中的数据,字节缓冲输入流BufferedInputStream;

    字节缓冲输出流BufferedOutputStream

    • public BuffeeredOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流;
    /**
     * 写数据到文件的方法
     * 1. 创建流
     * 2. 写数据
     * 3. 关闭流
     */
    //创建基本的字节输出流
    FileOutputStream fileOut = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
    //使用高效的流,把基本的流进行封装,实现速度的提升
    BufferedOutputStream out = new BufferedOutputStream(fileOut);
    //写数据
    out.write("hello".getBytes());
    out.close();
    

    字节缓冲输入流BufferedInputStream

    • public BufferedInputStream(InputStream in)
    /**
     * 从文件中读取数据
     * 1. 创建缓冲流对象
     * 2. 读数据
     * 3. 关闭
     */
    FileInputStream fileIn = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
    // 创建缓冲流对象,把基本的流包装成高效的流
    BufferedInputStream in = new BufferedInputStream(fileIn);
    byte[] bytes = new byte[1024];
    //读数据
    int len = 0;
    while ((len = in.read(bytes)) != -1) {
      System.out.println(new String(bytes, 0, len));
    }
    //关闭
    in.close();
    

    字符缓冲流

    • 字符缓冲输入流:BufferedReader;
    • 字符缓冲输出流:BufferedWriter;

    字符缓冲输出流BufferedWriter

    字符缓冲输出流BufferedWriter特有方法newLine

    • void newLine() 写换行;具有平台无关性;
    //创建字符输出流,封装文件
    FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
    BufferedWriter bfw = new BufferedWriter(fw);
    bfw.write(100);
    bfw.newLine();//换行
    bfw.flush();
    bfw.write("你好".toCharArray());
    bfw.newLine();
    bfw.flush();
    bfw.write("你好");
    bfw.newLine();
    bfw.flush();
    bfw.close();
    

    字节缓冲输入流BufferedReader

    从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取;

    • public String readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果到达流末尾,则返回null
    int lineNumber = 0;
    //创建字符缓冲输入流对象,构造方法传递字符输入流,包装数据源文件
    BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/2/abc.txt"));
    //循环调用缓冲流的方法readLine(),结束条件readLine方法返回null
    String line = null;
    while ((line = bfr.readLine()) != null) {
    lineNumber++;
    System.out.println(lineNumber + " " + line);
    }
    bfr.close();
    

    字符缓冲流复制文本文件

    public static void main(String[] args) throws IOException {
        int lineNumber = 0;
        //创建字符缓冲输入流对象,构造方法传递字符输入流,包装数据源文件
        BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/2/abc.txt"));
        BufferedWriter bfw = new BufferedWriter(new FileWriter("/Users/syjsuccess/Desktop/ceshi/1/abc.txt"));
        //读取文本行,读一行,写一行
        String line = null;
        while ((line = bfr.readLine()) != null) {
            bfw.write(line);
            bfw.newLine();
            bfw.flush();
        }
        bfw.close();
        bfr.close();
    }
    

    总结

    InputStream
            |-- FileInputStream
            |-- BufferedInputStream
    
    OutputStream
            |-- FileOutputStream
            |-- BufferedOutputStream
            
            
    Reader
            |-- InputStreamReader
                                |-- FileReader
            |-- BufferedReader
            
    Writer
            |-- OutputStreamWriter
                                |-- FileWriter
            |-- BufferedWriter
    
    字节输入流InputStream 字符输入流Reader
    FileInputStream操作文件的字节输入流 FileReader文件的字符输入流
    BufferedInputStream高效的字节输入流 BufferedReader高效的字符输入流
    InputStreamReader输入操作的转换流(把字节流封装成字符流)
    字节输出流OutputStream 字符输出流Writer
    FileOutputStream操作文件的字节输出流 FileWriter操作文件的字符输出流
    BufferedOutputStream高效的字节输出流 BufferedWriter高效的字符输出流
    OutputStreamWriter输出操作的转换流(把字节流封装成字符流)

    OutputStreamWriter类写文本文件

    OutputStreamWriter是字符流通向字节流的桥梁;可使用指定的字符编码表,将要写入流中的字符编码成字节;它的作用就是:将字符串按照指定的编码表转成字节,再使用字节流将这些字节写出去

    当调用OutputStreamWriter流对象的write方法时,会拿着字符到指定的码表中去进行查询,把查到的字符编码值转换成字节数存放到OutputStreamWriter缓冲区中,然后再调用刷新功能、或者关闭流、或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中;

    /*
     * 转换流对象OutputStreamWriter写文本
     * 采用UTF-8编码表写入
     */
    //创建字节输出流,绑定文件
    FileOutputStream fileOutputStream = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1/utf.txt");
    //创建转换对象,构造方法,保证字节输出流,并指定编码表是utf-8
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
    outputStreamWriter.write("你好");
    outputStreamWriter.close();
    
    /*
     * 转换流对象 OutputStreamWriter写文本
     * 文本采用GBK的形式写入
     */
    //创建字节输出流,绑定文件
    FileOutputStream fileOutputStream = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1/gbk.txt");
    //创建转换对象,构造方法,保证字节输出流,使用gbk编码表
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
    outputStreamWriter.write("你好");
    outputStreamWriter.close();
    

    InputStreamReader类读取文本文件

    InputStreamReader是字节流通向字符流的桥梁,它使用指定的字符编码表读取字节并将其解码问字符;

    /*
     *  转换流,InputSteamReader读取文本
     *  采用系统默认编码表,读取GBK文件
     */
    //创建字节输入流,传递文本文件
    FileInputStream fileInputStream = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/1/gbk.txt");
    //创建转换流对象,构造方法中,包装字节输入流,同时写编码表名
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");
    char[] ch = new char[1024];
    int len = inputStreamReader.read(ch);
    System.out.println(new String(ch, 0, len));//你好
    inputStreamReader.close();
    
    
    /*
     *  转换流,InputSteamReader读取文本
     *  采用UTF-8编码表,读取文件utf
     */
    //创建字节输入流,传递文本文件
    FileInputStream fileInputStream = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/1/utf.txt");
    //创建转换流对象,构造方法中,包装字节输入流,同时写编码表名
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
    char[] ch = new char[1024];
    int len = inputStreamReader.read(ch);
    System.out.println(new String(ch, 0, len));//你好
    inputStreamReader.close();
    
    

    转换流和它的子类区别

    继承关系:

    Writer
        |-- OutputStreamWriter
                            |-- FileWriter
    
    Reader
        |-- InputStreamReader
                            |-- FileReader
    
    OutputStreamWriter和InputStreamReader FileWriter和FileReader
    是字符和字节的桥梁;也可称之为字符转换流;转换原理:字节流+编码表 作为子类,仅作为操作字符文件的便捷类存在,当操作的字符文件使用的是默认编码表时可以不用父类
    /*
     * 以下三行代码作用一样,第三句最简便
     */
    InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//使用默认字符集
    InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "gbk");//指定gbk字符集
    FileReader fr = new FileReader("a.txt");
    

    一旦要指定其他编码时,就不能使用子类,必须使用字符转换流;

    字节--->字符 字符--->字节
    看不懂的--->看得懂的 看得懂的--->看不懂的

    缓冲流

    缓冲流概述:可提高IO流得读写速度分为字节缓冲流与字符缓冲流

    字节缓冲流

    • 写入数据到流中,字节缓冲输出流BufferedOutputStream;
    • 读取流中的数据,字节缓冲输入流BufferedInputStream;

    字节缓冲输出流BufferedOutputStream

    • public BuffeeredOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流;
    /**
     * 写数据到文件的方法
     * 1. 创建流
     * 2. 写数据
     * 3. 关闭流
     */
    //创建基本的字节输出流
    FileOutputStream fileOut = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
    //使用高效的流,把基本的流进行封装,实现速度的提升
    BufferedOutputStream out = new BufferedOutputStream(fileOut);
    //写数据
    out.write("hello".getBytes());
    out.close();
    

    字节缓冲输入流BufferedInputStream

    • public BufferedInputStream(InputStream in)
    /**
     * 从文件中读取数据
     * 1. 创建缓冲流对象
     * 2. 读数据
     * 3. 关闭
     */
    FileInputStream fileIn = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
    // 创建缓冲流对象,把基本的流包装成高效的流
    BufferedInputStream in = new BufferedInputStream(fileIn);
    byte[] bytes = new byte[1024];
    //读数据
    int len = 0;
    while ((len = in.read(bytes)) != -1) {
      System.out.println(new String(bytes, 0, len));
    }
    //关闭
    in.close();
    

    字符缓冲流

    • 字符缓冲输入流:BufferedReader;
    • 字符缓冲输出流:BufferedWriter;

    字符缓冲输出流BufferedWriter

    字符缓冲输出流BufferedWriter特有方法newLine

    • void newLine() 写换行;具有平台无关性;
    //创建字符输出流,封装文件
    FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
    BufferedWriter bfw = new BufferedWriter(fw);
    bfw.write(100);
    bfw.newLine();//换行
    bfw.flush();
    bfw.write("你好".toCharArray());
    bfw.newLine();
    bfw.flush();
    bfw.write("你好");
    bfw.newLine();
    bfw.flush();
    bfw.close();
    

    字节缓冲输入流BufferedReader

    从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取;

    • public String readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果到达流末尾,则返回null
    int lineNumber = 0;
    //创建字符缓冲输入流对象,构造方法传递字符输入流,包装数据源文件
    BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/2/abc.txt"));
    //循环调用缓冲流的方法readLine(),结束条件readLine方法返回null
    String line = null;
    while ((line = bfr.readLine()) != null) {
    lineNumber++;
    System.out.println(lineNumber + " " + line);
    }
    bfr.close();
    

    字符缓冲流复制文本文件

    public static void main(String[] args) throws IOException {
        int lineNumber = 0;
        //创建字符缓冲输入流对象,构造方法传递字符输入流,包装数据源文件
        BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/2/abc.txt"));
        BufferedWriter bfw = new BufferedWriter(new FileWriter("/Users/syjsuccess/Desktop/ceshi/1/abc.txt"));
        //读取文本行,读一行,写一行
        String line = null;
        while ((line = bfr.readLine()) != null) {
            bfw.write(line);
            bfw.newLine();
            bfw.flush();
        }
        bfw.close();
        bfr.close();
    }
    

    总结

    InputStream
            |-- FileInputStream
            |-- BufferedInputStream
    
    OutputStream
            |-- FileOutputStream
            |-- BufferedOutputStream
            
            
    Reader
            |-- InputStreamReader
                                |-- FileReader
            |-- BufferedReader
            
    Writer
            |-- OutputStreamWriter
                                |-- FileWriter
            |-- BufferedWriter
    
    字节输入流InputStream 字符输入流Reader
    FileInputStream操作文件的字节输入流 FileReader文件的字符输入流
    BufferedInputStream高效的字节输入流 BufferedReader高效的字符输入流
    InputStreamReader输入操作的转换流(把字节流封装成字符流)
    字节输出流OutputStream 字符输出流Writer
    FileOutputStream操作文件的字节输出流 FileWriter操作文件的字符输出流
    BufferedOutputStream高效的字节输出流 BufferedWriter高效的字符输出流
    OutputStreamWriter输出操作的转换流(把字节流封装成字符流)

    Properties类

    Properties介绍

    Properties类表示了一个持久的属性集,Properties可保存在流中或从流中加载,属性列表中每个键及其对应值都是一个字符串;

    特点:

    1. 是Hashtable的子类,map集合中的方法都可以用;
    2. 该集合没有泛型,键值都是字符串
    3. 它是一个可以持久化的属性集,键值可以存储到集合中,也可以存储到持久化的设备上,键值的来源也可以是持久化设备;
    4. 有和IO流技术相结合的方法(唯一一个能与IO流交互的集合);
    • Set<String> stringPropertyNames() 将集合中的键存储到Set集合,类似Map接口的方法keySet;
    Properties pro = new Properties();
    pro.setProperty("a", "1");
    pro.setProperty("b", "2");
    pro.setProperty("c", "3");
    System.out.println(pro);//{b=2, a=1, c=3}
    
    String value = pro.getProperty("c");//3
    System.out.println(value);
    //方法stringPropertyNames,将集合中的键存储到Set集合,类似Map接口的方法keySet
    Set<String> set = pro.stringPropertyNames();
    for(String key : set) {
      System.out.println(key + "..." + pro.getProperty(key));
    }
    /**
     * b...2
     * a...1
     * c...3
     */
    

    Properties集合的方法load

    传递任意的字节或者字符输入流,流对象读取文件中的键值对,保存到集合;

    • void load(InputStream inStream) 输入流中读取属性列表(键值对);
    • void load(Reader reader) 按简单的面相行的格式从输入字符流中读取属性列表(键值对);
    /**
     *  1. 创建集合
     *  2. 创建流对象
     *  3. 把流所对应文件中的数据读取到集合中
     *  4. 关闭流
     *  5. 显示集合中的数据
     */
    Properties pro = new Properties();
    FileReader fr = new FileReader("/Users/syjsuccess/Desktop/ceshi/output.txt");
    //调用集合的方法load,传递字符输入流
    pro.load(fr);
    fr.close();
    System.out.println(pro);//{abc=123}
    

    Properties集合的方法store

    接收所有的字节或者字符的输出流,将集合中的键值对,写回文件中保存;

    • void store(OutputStream out, String comments)

    • void store(Writer writer, String comments)

    /**
     * 1. 创建Properties集合
     * 2. 添加元素到集合
     * 3. 创建流
     * 4. 把集合中的数据存储到流所对应的文件中
     * 5. 关闭流
     */
    Properties pro = new Properties();
    pro.setProperty("name", "zhangsan");
    pro.setProperty("age", "27");
    pro.setProperty("email", "12233@qq.com");
    FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/output.txt");
    //键值对,存回文件,使用集合的方法store传递字符输出流
    pro.store(fw, "");
    fw.close();
    

    对象的序列化和反序列化

    • 对象的序列化:对象中的数据,以流的形式写入到文件中保存的过程称为写出对象,对象的序列化;ObjectOutputStream将对象写到文件中,实现序列化;
    • 对象的反序列化:在文件中,以流的形式将对象读取,对象的反序列化;ObjectInputStream将文件对象读取出来;

    ObjectOutputStream流写对象

    • ObjectOutputStream(OutputStream out) 创建写入指定OutputStream的ObjectOutputStream;
    • void writeObject() 将指定的对象写入ObjectOutputStream;
    //创建字节输出流,封装文件
    FileOutputStream fos = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/output.txt");
    //创建写出对象的序列化流的对象,构造方法传递字节输出流
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    Person p = new Person("lisi", 25);
    //调用序列化流的方法writeObject,写出对象
    //implements Serializable
    oos.writeObject(p);
    oos.close();
    

    ObjectInputStream流读取对象

    • ObjectInputStream(InputStream in) 创建从指定InputStream读取的ObjectInputStream;
    • Object readObject() 从ObjectInputStream读取对象;
    FileInputStream fis = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/output.txt");
    //创建反序列化流,构造方法中,传递字节输入流
    ObjectInputStream ois = new ObjectInputStream(fis);
    //调用反序列化方法,readObject()
    Object obj = ois.readObject();
    System.out.println(obj);//Person{name='lisi', age=25}
    ois.close();
    

    静态不能序列化

    原因:序列化是把对象数据进行持久化存储,而静态的东西不属于对象,属于类

    transient关键字

    当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰,只要被transient修饰了,序列化时这个属性就不会被序列化了;

    被transient修饰的属性不会被序列化,transient关键字只能修饰成员变量

    private transient int age;
    

    Serializable接口的含义

    当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口,否则会发生异常NotSerializableException异常;

    Serializable标记接口,该接口给需要序列化的类提供了一个序列版本号,serialVersionUID,该版本号的目的在于验证序列化的对象喝对应类是否版本匹配;

    给需要序列化的类加上标记,该标记中没有任何抽象方法;只有实现了Serializable接口的类的对象才能被序列化

    序列化中的序列号冲突问题

    当一个类实现Serializable接口后,创建对象并将对象写入文件,之后更改了源码(比如:将成员变量的修饰符private改成public),再次从文件中读取对象时会报InvalidClassException异常,

    序列化中自定义的序列号

    定义方式:private static final long serialVersionUID = xxxxxxxxxxxxL;

    这样每次编译类是生成的serialVersionUID值都是固定的;

    //类自定义了序列号,编译器不会计算序列号
    private static final long serialVersionUID = 1234444555L;
    

    打印流

    打印流和特性

    概述:打印流添加输出数据的功能,使它们能够方便地打印各种数据值表示形式;

    打印流根据流分类:字节打印流PrintStream字符打印流PrintWriter;

    • void print(String str) 输出任意类型的数据;
    • void println(String str) 输出任意类型的数据,自动写入换行操作;

    特点:

    1. 此流不负责数据源,只负责数据目的
    2. 为其他输出流,添加功能;
    3. 永远不会抛出IOException,但是可能抛出别的异常;
    4. 两个打印流的方法,完全一致;
    5. 构造方法就是打印流的输出目的端;
    • PrintStream构造方法:接收File类型、接收字符串文件名、接收字节输出流OutputStream;
    • PrintWriter构造方法:接收File类型、接收字符串文件名、接收字节输出流OutputStream、接收字符输出流Writer;

    打印输出目的是File对象

    /**
     * 打印流,向File对象的数据目的写入数据
     * 方法print println 原样输出
     * write方法走码表
     */
    File file = new File("/Users/syjsuccess/Desktop/ceshi/1.txt");
    PrintWriter pw = new PrintWriter(file);
    pw.println(true);
    pw.write(100);
    pw.close();
    

    输出语句是char数组

    print和println只有打印字符数组是打印内容,其余都是打印数组的地址;

    int[] arr = {1};
    System.out.println(arr);//[I@1f89ab83
    char[] ch = {'a', 'b'};
    System.out.println(ch);//ab
    byte[] b = {};
    System.out.println(b);//[B@e73f9ac
    

    打印流输出目的是String和流对象

    /**
     * 打印流输出目的是流对象
     * 可以是字节输出流,可以是字符输出流
     * OutputStream Writer
     */
    FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/1.txt");
    PrintWriter pw = new PrintWriter(fw);
    pw.println("打印流");
    pw.close();
    
    /**
     * 打印流输出目的是String文件名
     */
    PrintWriter pw = new PrintWriter("/Users/syjsuccess/Desktop/ceshi/1.txt");
    pw.println(3.5);
    pw.close();
    

    打印流开启自动刷新

    /**
     * 打印流可以开启自动刷新功能
     * 满足2个条件:
     *  1. 输出的数据目的必须是流对象OutputStream Writer
     *  2. 必须调用println printf format三个方法中的一个
     */
    FileOutputStream fos = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1.txt");
    PrintWriter pw = new PrintWriter(fos, true);
    pw.println("i");
    pw.println("love");
    pw.println("java");
    pw.close();
    

    打印流复制文本文件

    /**
     * 打印流实现文本复制
     *      读取数据源 BufferedReader + File 读取文本行
     *      写入数据目的 PrintWriter + println自动刷新
     */
    BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/1.txt"));
    PrintWriter pw = new PrintWriter(new FileWriter("/Users/syjsuccess/Desktop/ceshi/2.txt"));
    String line = null;
    while ((line = bfr.readLine()) != null) {
      pw.println(line);
    }
    pw.close();
    bfr.close();
    

    commons-IO

    commons-io工具类介绍

    解压缩commons-io-2.4.zip文件;

    commons-io-2.4.jar是需要导入到项目中的jar包,里面存放的是class文件;

    commons-io-2.4-sources.jar是工具类中的源码;

    docs是帮助文档;

    使用工具类commons-io

    导入jar包:

    (idea)

    1. 创建lib文件夹,将commons-io-2.4.jar复制到lib文件夹;
    2. 右键,add as a Library;
    3. 右键,building xxx;

    (eclipse)

    1. 创建lib文件夹,将commons-io-2.4.jar和common-io-2.4.jar复制到lib文件夹;
    2. 右键commons-io-2.4.jar,build path,add to build path;

    IO工具类FilenameUtils

    • getExtension(String path) 获取文件的扩展名;

      /**
       * static String getExtension(String fileName)
       * 获取文件扩展名
       */
      String name = FilenameUtils.getExtension("/Users/syjsuccess/Desktop/ceshi/output.txt");
      System.out.println(name);//txt
      
    • getName() 获取文件名;

      /**
       * static String getName(String fileName)
       * 获取文件名
       */
      String name = FilenameUtils.getName("/Users/syjsuccess/Desktop/ceshi/output.txt");
      System.out.println(name);//output.txt
      
    • isExtension(String filName, String ext) 判断fileName是否是ext后缀名;

      /**
       * static boolean isExtension(String filename, String extension)
       * 判断文件名的扩展是不是extension
       */
      boolean b = FilenameUtils.isExtension("Demo.java", "java");
      System.out.println(b);//true
      

    IO工具类FileUtils

    • writeStringToFile(File file, String content) 将内容content写入到file中;

      /**
       * static void writeStringToFile(File file, String str)
       * 将字符串直接写到文件中
       */
      File file = new File("/Users/syjsuccess/Desktop/ceshi/1.txt");
      FileUtils.writeStringToFile(file, "I love Java Programming");
      
    • copyDirectoryToDirectory(File srcDir, File destDir) 文件复制;

      /**
       * static void copyDirectoryToDirectory(File src, File dest)
       * 复制文件夹
       */
      File fileSrc = new File("/Users/syjsuccess/Desktop/ceshi/1/src");
      File fileDest = new File("/Users/syjsuccess/Desktop/ceshi/2");
      FileUtils.copyDirectoryToDirectory(fileSrc, fileDest);
      
    • copyFile(File srcFile, File destFile) 文件复制;

      /**
       * static void copyFile(File src, File dest)
       * 复制文件
       */
      File fileSrc = new File("/Users/syjsuccess/Desktop/ceshi/1/src/对象的序列化.JPG");
      File fileDest = new File("/Users/syjsuccess/Desktop/ceshi/2/src/对象的序列化.JPG");
      FileUtils.copyFile(fileSrc, fileDest);
      
    • readFileToString(File file) 读取文件内容,并返回一个String;

      /**
       * static String readFileToString(File src)
       * 读取文本,返回字符串
       */
      File file = new File("/Users/syjsuccess/Desktop/ceshi/1.txt");
      String str = FileUtils.readFileToString(file);
      System.out.println(str);//I love Java Programming
      

    总结

    字节流

    字节输入流InputStream 字节输出流OutputStream
    FileInputStream---操作文件的字节输入流 FileOutputStream---操作文件的字节输出流
    BufferedInputStream---高效的字节输入流 BufferedOutputStream---高效的字节输出流
    ObjectInputStream---反序列化流 ObjectOutputStream---序列化流
    PrintStream---字节打印流

    字符流

    字符输入流Reader 字符输出流Writer
    **FileReader **---操作文件的字符输入流 **FileWriter **---操作文件的字符输出流
    BufferedReader ---高效的字符输入流 **BufferedWriter **---高效的字符输出流
    InputStreamReader ---输入操作的转换流(把字节流封装成字符流) **OutputStreamWriter **---输出操作的转换流(把字节流封装成字符流)
    **PrintWriter **---字符打印流

    方法:

    读取数据方法 写数据方法
    read()---一次读一个字节/字符的方法 write() ---一次写一个字节/字符到文件中
    read(byte[]/char[])---一次读一个数组数据的方法 write(byte[]/char[]) ---一次写一个数组数据到文件中
    readLine() ---一次读一行字符串的方法(BufferedReader类特有的方法 write(String) ---一次写一个字符串内容到文件中
    readObject() ---从流中读取对象(ObjectInputStream特有方法 writeObject(Object) ---写对象到流中(ObjectOutputStream类特有方法
    newLine() ---写一个换行符号(BufferedWriter类特有方法

    向文件中写入数据的过程

    1. 创建输出流对象;
    2. 写数据到文件;
    3. 关闭输出流;

    从文件中读取数据的过程

    1. 创建输入流对象;
    2. 从文件中读数据;
    3. 关闭输入流;

    文件复制过程

    1. 创建输出流(数据源);
    2. 创建输出流(目的地);
    3. 从输入流中读取数据;
    4. 通过输出流,把数据写入目的地;
    5. 关闭流;

    File类方法

    • getName() 获取文件名称;
    • getAbsolutePath() 获取文件绝对路径获取文件大小;
    • length() 获取文件大小;
    • File[] listFile() 获取当前文件夹中所有File对象;
    • isFile() 判断是否为文件;
    • isDirectory() 判断是否为文件夹;
    • mkdir() mkdirs() 创建文件夹
    • createNewFile() 创建文件;

    异常

    try...catch...finally 捕获处理异常;

    throws 声明异常;

    throw 抛出异常对象;

    异常的分类

    编译期异常:Exception;

    ​ |--- 运行期异常:RuntimeException;

    编译期异常必须处理,不然无法编译通过;

    运行期异常,程序运行过程中产生的异常信息;

    Properties

    Map集合的一种,它是Hashtable集合的子集合,它键和值都是String类型;是唯一能和IO流结合使用的集合;

    • load(InputStream in) 从流所对应的文件中读取数据到集合中;
    • load(Reader in) 从流所对应的文件中,读数据到集合中;
    • store(OutputStream out, String message) 把集合中的数据,写入到流所对应的文件中;
    • store(Writer out, String message) 把集合中的数据,写入到流所对应的文件中;

    实现文件内容的自动追加

    • 构造方法
    • FileOutputStream(File file, boolean append)
    • FileOutputStream(String fileName, boolean append)
    • FileWriter(File, boolean append)
    • FileWriter(String fileName, boolean append)

    实现文件内容的自动刷新

    • 构造方法
    • PrintStream(OutputStream out, boolean autoFlush)
    • PrintWriter(OutputStream out, boolean autoFlush)
    • PrintWriter(Writer out, boolean autoFlush)

    commons-IO

    • readFileToString(File file) 读取文件内容,并返回一个String;
    • writeStringtoFile(File file, String content) 将内容content写入到file中;
    • copyDirectoryToDirectoty(File srcDir, File destDir) 文件夹复制;
    • copyFileToDirectory(File srcFile, File destFile) 文件复制;

    相关文章

      网友评论

          本文标题:IO流对象

          本文链接:https://www.haomeiwen.com/subject/aveeahtx.html