登录后台

页面导航

本文编写于 214 天前,最后修改于 214 天前,其中某些信息可能已经过时。

一. IO流

  1. 定义

    • IO流用来处理设备之间的数据传输
    • Java对数据的操作是通过流的方式
    • Java用于操作流的类都在IO包中
    • 流按流向分为两种:输入流,输出流。I/O
    • 流按操作类型分为两种:

      • 字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
      • 字符流 : 字符流只能操作纯字符数据,比较方便。
  2. IO流常用父类

    • 字节流的抽象父类:

      • InputStream
      • OutputStream
    • 字符流的抽象父类:

      • Reader
      • Writer
  3. IO流图解

IO流

  1. 使用步骤

    • 使用前,导入IO包中的类
    • 使用时,进行IO异常处理
    • 使用后,释放资源

二. 字节流之FileInputStream

  1. 定义

    • 以字节的形式来读取文件内容
    • InputStream抽象类的子类, 已经重写了read()方法
  2. 构造方法

    • FileInputStream(String name) : 根据字符串地址来连接到一个本地文件
    • FileInputStream(File file) : 根据一个File类对象连接到一个本地文件
  3. 常用方法

    • read() : 从此输入流中读取一个数据字节
    • read(byte[] b) : 从此输入流中将最多b.length个字节的数据读入一个byte数组中
    • read(byte[] b,int off,int len) : 从此输入流中读取最多 len个字节的数据读入到一个byte[] 数组中
    • close() : 关闭此输入流并释放与此流有关的所有系统资源
  4. 演示

    public static void main(String[] args) throws Exception {
        //创建输入流连接
        FileInputStream inputStream = new FileInputStream("d:\\xidada.jpg");
        //定义接收数据的变量
        int i = 0;
        //从输入流中读取一个字节(如果返回-1,说明已经到了文件的末尾)
        while ((i = inputStream.read())!=-1) {
            System.out.println(i);
        }
        //关闭流
        inputStream.close();
    }
  5. 思考题

    • read()方法读取的是一个字节,为什么返回是int,而不是byte ?
    • 因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111,那么11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型

三. 字节流之FileOuputStream

  1. 定义

    • 以字节的形式将数据写入到文件中
    • OutputStream抽象类的子类, 已经重写了write()方法
  2. 构造方法

    • FileOuputStream(String name) : 根据字符串地址来连接到一个本地文件
    • FileOuputStream(File file) : 根据一个File类对象连接到一个本地文件
    • FileOuputStream(File file,boolean append) : 在文件末尾继续写入
  3. 常用方法

    • write(int b) : 将指定字节写入此文件输出流
    • write(byte[] b) : 将b.length个字节从指定byte数组写入此文件输出流中
    • write(byte[] b,int off, int len) : 将指定byte数组中从偏移量off开始的len个字节写入此文件输出量
    • close() : 关闭输出流并释放与此流有关的所有系统资源
  4. 演示

    public static void main(String[] args) throws Exception {
        
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\ddd.txt");
        
        fileOutputStream.write(97);
    
        fileOutputStream.close();
    
    }
  5. 尾部追加

    • FileOutputStream为我们提供了尾部添加的形式, 我们利用FileOuputStream(File file,boolean append)构造方法创建的对象,就可以将流中的内容追加到文件的尾部
    • 在将多个文件合并成一个的时候可以使用
    • 演示

      public static void main(String[] args) throws Exception {
          
          FileOutputStream fos = new FileOutputStream("d:\\合成文件.txt",true);
          
          
          FileInputStream fis1 = new FileInputStream("d:\\碎片1.txt");
          FileInputStream fis2 = new FileInputStream("d:\\碎片2.txt");
          FileInputStream fis3 = new FileInputStream("d:\\碎片3.txt");
          
          int i ;
          while ((i=fis1.read())!=-1) {
              fos.write(i);
          }
          while ((i=fis2.read())!=-1) {
              fos.write(i);
          }
          while ((i=fis3.read())!=-1) {
              fos.write(i);
          }
          
          fis1.close();
          fis2.close();
          fis3.close();
          
          fos.close();
      }

四. 读写练习

  1. 复制图片

    • 需求: 将一张图片复制到其他地方
    • 解析: 使用FileInputStream读取 , 使用FileOutputStream写入
    • 演示

      public static void main(String[] args) throws Exception {
          
          FileInputStream fis = new FileInputStream("d:\\xidada.jpg");
          FileOutputStream fos = new FileOutputStream("d:\\副本.jpg");
          int i = 0;
          while ((i=fis.read())!=-1) {
              fos.write(i);
          }
          fis.close();
          fos.close();
      }
  2. 复制歌曲

    • 需求: 将一首歌曲复制到其他地方
    • 解析: 使用FileInputStream读取 , 使用FileOutputStream写入
    • 演示

      public static void main(String[] args) throws Exception {
          
          FileInputStream fis = new FileInputStream("d:\\骑在银龙的背上.mp3");
          FileOutputStream fos = new FileOutputStream("d:\\音乐副本.mp3");
          int i = 0;
          while ((i=fis.read())!=-1) {
              fos.write(i);
          }
          fis.close();
          fos.close();
      }
    • 分析: 速度太慢

五. 小数组读写

  1. 定义

    • 每次读取一个字节的速度实在是太慢了,实际开发中根本无法使用
    • 所以,java为我们提供了一次获取多个字节的方法, read(byte[] b), 允许一次获取一个数组长度的字节
  2. available()方法

    • 这个方法可以帮我们获取资源中剩余的长度
    • 所有我们可以创建一个和资源文件大小相等长度小数组来装载数据

      public static void main(String[] args) throws Exception {
          
          FileInputStream fis = new FileInputStream("d:\\骑在银龙的背上.mp3");
          FileOutputStream fos = new FileOutputStream("d:\\音乐副本.mp3");
          
          //创建一个和资源文件大小相同的字节数组
          byte[] bs = new byte[fis.available()];
          
          fis.read(bs);
          fos.write(bs);
          
          fis.close();
          fos.close();
      }
    • 如果资源文件过大的话,很容易造成内存溢出
    • 获取长度的速度极慢, 不可取
  3. 标准写法

    • 定义的小数组的长度不宜过长也不宜过短
    • 多长容易造成内存溢出, 过短效率低下
    • 演示

      public static void main(String[] args) throws Exception {
          
          FileInputStream fis = new FileInputStream("d:\\骑在银龙的背上.mp3");
          FileOutputStream fos = new FileOutputStream("d:\\音乐副本.mp3");
          
          //创建一个和资源文件大小相同的字节数组
          byte[] bs = new byte[1024*8];
          int len = 0;
          while((len=fis.read(bs))!= -1){
                //最后一次读取的时候可能并不能装满整个数组
              fos.write(bs, 0, len);
          }
          
          fis.close();
          fos.close();
      }
  4. 测试题

    • 需求: 从键盘录入文字, 保存到本地文件中, 直到录入quit时就退出
    • 解析: 字符串要转换成字节数组

六. 图片加密

  • 对图片的每一个字节进行加密
  • 演示

    public static void main(String[] args) throws Exception {
        
        FileInputStream fis = new FileInputStream("d:\\图片副本.jpg");
        FileOutputStream fos = new FileOutputStream("d:\\图片副本2.jpg");
        
        int i = 0;
        while((i=fis.read())!= -1){
            //对每一个字节进行加密
            fos.write(i^123); 
        }
        fis.close();
        fos.close();
    }

七. 字节输入缓冲流(BufferedInputStream)

  1. 定义

    • 我们都知道单个字节的读取是效率非常低下的, 所以我们使用了小数组的方法进行流的读取和写入
    • java中已经帮我们实现了, 这就是缓冲区的概念, 也是一次性读取一个数组,然后将这个数组放入内存中供我们使用
    • 缓冲流只是一个壳,实际还是字节流在工作
  2. 构造方法

    • BufferedInputStream(InputStream in)

      • 创建一个BufferedInputStream 并保存其参数, 即输入in ,一遍将来使用
    • BuffferedInputStream(InputStream in , int size)

      • 创建一个具有指定缓冲区大小的BufferedInputStream并保存其参数, 即输入流in,以便将来使用
  3. 常用方法

    • read() : 一次读取一个字节
    • read(byte[] b, int off, int len) : 从此字节输入流中给定偏移量处开始各字节读取到指定的byte数组中
    • close() : 关闭并释放资源,实际关闭的是内部真正工作的字节流
  4. 注意事项

    • BufferedInputStream内部建立一个缓冲区域,在读取文件的时候, 一次性读取大量的字节, 缓冲到缓冲区当中, 然后再反给我们, 看着没有变化, 区别在于一个直接操作硬盘, 一个是操作内存, 效率不可相提并论
  5. 演示

    public static void main(String[] args) throws Exception {
        
        FileInputStream fis = new FileInputStream("d:\\图片副本.jpg");
        
        BufferedInputStream bis = new BufferedInputStream(fis);
        
        int i ;
        while((i=bis.read())!=-1){
            System.out.println(i);
        }
        //关闭缓冲流就会关闭字节流
        bis.close();
    }

八. 字节输出缓冲流(BufferedOutputStream)

  1. 定义

    • 单个字节的写入是效率及其低下的, 所以我们使用了小数组的形式进行写入, 一次写入一个数组的数据
    • java中给我们提供了输出缓冲区流,将我们写的字节先存放到一个小数组中,等数组满了之后再写入到本地去
    • 在流关闭之前, 会有一次写入动作, 这样就避免了最后一次读取时, 缓冲区没有满不能写入的问题
  2. 构造方法

    • BufferedOutputStream(OutputStram out)

      • 创建一个新的缓冲输出流,以将数据写入指定的底层输出流
    • BufferedOutputStream(OutputStream out, int size)

      • 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流
  3. 常用方法

    • write(int b) : 将指定的字节写入此缓冲流的输出流
    • write(byte[] b, int off, int len) : 将指定byte数组中从偏移量off开始的len个字节吸入此缓冲流的输入流
    • flush() : 刷新此缓冲流的输出流
    • close() : 关闭流,并释放资源
  4. 演示

    public static void main(String[] args) throws Exception {
        
        FileOutputStream fos = new FileOutputStream("d:\\ddd.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        for (int i = 0; i < 10000; i++) {
            bos.write(97);
        }
        
        bos.close();
    }
  5. 注意事项

    • 缓冲流就一个壳, 他不能实际和本地文件建立连接, 本质还是通过InputStream和OutputStream来工作

九. 使用字节缓冲流来实现文件的复制

  1. 演示

    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("d:\\骑在银龙的背上.mp3");
        BufferedInputStream bis = new BufferedInputStream(fis);
        
        FileOutputStream fos = new FileOutputStream("d:\\音乐副本.mp3");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        
        int i ;
        while((i=bis.read())!= -1){
            bos.write(i);
        }
        
        bis.close();
        bos.close();
    }
  2. 测试题

    • 需求: 将一个文件夹复制到另一个地方
    • 演示

      public static void copy(String srcname,String target) throws Exception{
          
          File srcFile = new File(srcname);
          
          File targetFile = new File(new File(target),srcFile.getName());
          
          targetFile.mkdir();
          
          File[] files = srcFile.listFiles();
          if(files!=null){
              for (File file : files) {
                  if (file.isFile()) {
                      FileInputStream fis = new FileInputStream(file);
                      //targetFile+文件名
                      File file2 = new File(targetFile,file.getName());
                      FileOutputStream fos = new FileOutputStream(file2);
                      
                      byte[] bs = new byte[1024*8];
                      int len ;
                      while((len=fis.read(bs))!=-1){
                          fos.write(bs,0,len);
                      }
                      fis.close();
                      fos.close();
                  }else{
                      copy(file.getAbsolutePath(),targetFile.getAbsolutePath());
                  }
              }
              
          }
      }
  3. 小数组和缓冲流的效率问题

    • 定义小数组如果是8192个字节大小和Buffered比较的话,小数组块
    • 定义小数组会略胜一筹,因为读和写操作的是同一个数组
    • 而Buffered操作的是两个数组

十. 流的异常处理问题

  1. jdk1.6及以前的版本处理方式

    public static void main(String[] args)  {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("d:\\骑在银龙的背上.mp3");
            fos = new FileOutputStream("d:\\音乐副本.mp3");
            int i ;
            while((i=fis.read())!= -1){
                fos.write(i);
            }
        } catch (Exception e) {
            
        }finally {
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
                
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  2. jdk1.7的处理方式

    • 在try()中创建的流对象必须实现了AutoCloseable这个接口,如果实现了,在try后面的{}(读写代码)执行后就会自动调用,流对象的close方法将流关掉
    public static void main(String[] args)  {
        try(
            FileInputStream fis = new FileInputStream("d:\\骑在银龙的背上.mp3");
            FileOutputStream fos = new FileOutputStream("d:\\音乐副本.mp3");
        ){
            int i ;
            while((i=fis.read())!= -1){
                fos.write(i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

已有 112 条评论