JavaIO流

一、什么是IO

  • IO又分为流IO(java.io)

  • 块IO(java.nio)

二、流

java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。

将数据从外存中读取到内存中的称为输入流

将数据从内存写入外存中的称为输出流

1. 分类

  • 输入流、输出流——流向

    • 源 ----> 目标
      • 程序 <--- 文件 —— 输入流
      • 程序 ---> 文件 —— 输出流
  • 字节流、字符流——传输数据单位

    image-20201121165947186

    • 这四大基流都是抽象类(无法实例化),其他流都是继承于这四大基流的。
    • 字节流——数据流中最小的数据单元是字节
    • 字符流:数据流中最小的数据单元是字符
      • Java中的字符是Unicode编码,一个字符占用两个字节(无论中文还是英文都是两个字节)。
  • 节点流和包装流——功能

    • 节点流:可以从或向一个特定的地方(节点)读写数据,直接连接数据源。
      • 如最常见的是文件的FileReader,还可以是数组、管道、字符串,关键字分别为ByteArray/CharArray,Piped,String。.
    • 处理流(包装流):并不直接连接数据源,是对一个已存在的流的连接和封装,是一种典型的装饰器设计模式,使用处理流主要是为了更方便的执行输入输出工作
      • 如PrintStream,输出功能很强大,又如BufferedReader提供缓存机制,推荐输出时都使用处理流包装。
  • 一些特别的的流类型

    • 转换流:转换流只有字节流转换为字符流,因为字符流使用起来更方便,我们只会向更方便使用的方向转化。如:InputStreamReader与OutputStreamWriter。
    • 缓冲流:有关键字Buffered,也是一种处理流,为其包装的流增加了缓存功能,提高了输入输出的效率,增加缓冲功能后需要使用flush()才能将缓冲区中内容写入到实际的物理节点。但是,在现在版本的Java中,只需记得关闭输出流(调用close()方法),就会自动执行输出流的flush()方法,可以保证将缓冲区中内容写入。
    • 对象流:有关键字Object,主要用于将目标对象保存到磁盘中或允许在网络中直接传输对象时使用(对象序列化)
image-20201121161527846

2. IO操作模板

  ①、创建源或目标对象

    输入:把文件中的数据流向到程序中,此时文件是源,程序是目标

    输出:把程序中的数据流向到文件中,此时文件是目标,程序是源

  ②、创建 IO 流对象

    输入:创建输入流对象

    输出:创建输出流对象

  ③、具体的 IO 操作

  ④、关闭资源

    输入:输入流的 close() 方法

    输出:输出流的 close() 方法

程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资源。如果不关闭该资源,那么磁盘的文件将一直被程序引用着,不能删除也不能更改。所以应该手动调用 close() 方法关闭流资源

3. File类

文件和目录路径名的抽象表示。

  • File字段

    • 为了屏蔽各个平台之间的分隔符差异

      File.separator//系统分隔符
      
      • UNIX平台,绝对路径名的前缀始终为"/"
      • 而Windows平台,相对路径"/",绝对路径则用"\\"
      File file1 = new File("src/hello1.txt");
      File file2 = new File("src"+File.separator+"hello1.txt");
      
  • 构造方法

    image-20201121202201119

    //从父抽象路径名和子路径名字符串创建新的 File实例。 
    File file = new File("scr");
    File file1 = new File(file,"hello1.txt");
    System.out.println(file1);//scr\hello1.txt
    //通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。 
    File file2 = new File("src"+File.separator+"hello1.txt");
    System.out.println(file2);//scr\hello1.txt
    //从父路径名字符串和子路径名字符串创建新的 File实例。
    File file3 = new File("scr","hello1.txt");
    System.out.println(file3);//scr\hello1.txt
    
  • 常用方法

    1. 创建方法

      • boolean createNewFile() 不存在返回true 存在返回false

      • boolean mkdir() 创建目录,如果上一级目录不存在,则会创建失败

      • boolean mkdirs() 创建多级目录,如果上一级目录不存在也会自动创建

    2. 删除方法

      • boolean delete() 删除文件或目录,如果表示目录,则目录下必须为空才能删除
      • boolean deleteOnExit() 文件使用完成后删除
    3. 判断方法

      • boolean canExecute()判断文件是否可执行
      • boolean canRead()判断文件是否可读
      • boolean canWrite() 判断文件是否可写
      • boolean exists() 判断文件或目录是否存在
      • boolean isDirectory() 判断此路径是否为一个目录
      • boolean isFile()  判断是否为一个文件
      • boolean isHidden()  判断是否为隐藏文件
      • boolean isAbsolute()判断是否是绝对路径 文件不存在也能判断
    4. 获取方法

      • String getName() 获取此路径表示的文件或目录名称

      • String getPath() 将此路径名转换为路径名字符串

      • String getAbsolutePath() 返回此抽象路径名的绝对形式

      • String getParent()//如果没有父目录返回null

      • long lastModified()//获取最后一次修改的时间

      • long length() 返回由此抽象路径名表示的文件的长度。

      • boolean renameTo(File f) 重命名由此抽象路径名表示的文件。

      • File[] liseRoots()//获取机器盘符

      • String[] list() 返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。

      • String[] list(FilenameFilter filter) 返回一个字符串数组,命名由此抽象路径名表示的目录中满足指定过滤器的文件和目录。

        public class TestFile2 {
            public static void main(String[] args) throws IOException {
                File dir = new File("Hello");
                File file = new File(dir,"hello1");
        
                if(!dir.exists()||dir.isDirectory()) {
                    dir.mkdirs();
                    file.createNewFile();
                }
        
                System.out.println(file.getName());
                System.out.println(file.getPath());
                System.out.println(file.getParent());
            }
        }	
        

4. 字节流

image-20201121210103051
  • InputStream

    用 字节输出流 InputStream 的典型实现 FileInputStream

    public class FileDemo extends File{
        public FileDemo() {
            super("src/hello.txt");//helloworld
        }
    }
    
    public class FileInputStreamDemo {
        public FileInputStreamDemo() throws IOException {
            FileDemo file = new FileDemo();
            InputStream in = new FileInputStream(file);
    
            //逐字读取
            byte[] buffer = new byte[(int)file.length()];
            int count = 0;
            byte temp;
    
            while ((temp = (byte) in.read())!= (-1)) {
                buffer[count++] = temp;
            }
    
            in.close();
            System.out.println(new String(buffer));
        }
    
        public static void main(String[] args) throws IOException {
            new FileInputStreamDemo();
        }
    }
    //helloword
    
  • OutputStream

    OutputStream 的典型实现 FileOutputStream

    public class FileOutputStreamDemo {
        public FileOutputStreamDemo() throws IOException {
            FileDemo file = new FileDemo();
    
            FileOutputStream out = new FileOutputStream(file, true);
            
            //写入
            out.write("\n".getBytes());
            out.write(65);
            out.write("\n".getBytes());
            out.write("this is a demo\n".getBytes());
            out.write("abcdefghijk\n".getBytes(),1,4);
    
            out.close();
        }
    
        public static void main(String[] args) throws IOException {
            new FileOutputStreamDemo();
            new FileInputStreamDemo();
        }
    }
    /*
    helloworld
    A
    this is a demo
    bcde
    */
    
  • 用字节流完成文件的复制

    hello1.txt的内容变成hello.txt中的helloworld

    public class CopeText {
    
        public static void main(String[] args) throws IOException {
            //1.创建源和目标
            File source = new File("src/hello.txt");//helloworld
            File target = new File("src/hello1.txt");//this is hello1
    
            //2.创建输入输出对象
            InputStream in = new FileInputStream(source);
            OutputStream out = new FileOutputStream(target);
    
            //3.读取和写入操作
            byte[] buffer = new byte[100];
            int count = 0;
            int temp;
            while ((temp = in.read()) != (-1)) {
                buffer[count++] = (byte) temp;
            }
    
            out.write(buffer);
    
            //4.关闭流资源
            in.close();
            out.close();
        }
    }
    

5. 字符流

  • 为什么要使用字符流?

    ​ 因为使用字节流操作汉字或特殊符号语言的时候容易乱码,因为汉字不止一个字节,为了解决这个问题,建议使用字符流。

  • 什么情况下使用字符流?

    一般可以用记事本打开的文件,我们可以看到内容不乱码的。就是文本文件,可以使用字符流。

    ​ 而操作二进制文件(比如图片、音频、视频)必须使用字节流

    image-20201122145240689
    • FileWriter

      用字符输出流 Writer 的典型实现 FileWriter 来介绍这个类的用法

      public class FileWriterDemo {
      
          public static void main(String[] args) throws IOException {
              //1.创建源
              File file = new File("src", "hello.txt");//helloworld
      
              //2.创建输出对象
              Writer out = new FileWriter(file);
      
              //3.写入操作
              out.write("春暖花开\n");
              out.write(65);
              out.write("\n".toCharArray());
              out.write("零一二三四五六七".toCharArray(),3,4);
      
              //4.关闭流资源
              out.close();
          }
      
      }
      

      打开hello.txt查看内容可以看见,不会显示乱码

      春暖花开
      A
      三四五六

    • Reader

      用字符输入流 Reader 的典型实现 FileReader 来介绍这个类的用法:

      public class FileReaderDemo {
          public static void main(String[] args) throws IOException {
              //1.创建源
              File file = new File("src/hello.txt");
      
              //2.创建流对象
              Reader in = new FileReader(file);
      
              //3.读取操作
              int len;
      
                  //读取全部
              while ((len = in.read()) != (-1)) {
                  System.out.print((char)len);
              }
      
                  
              char[] buffer = new char[12]; //将字符读进字符数组,每次读12个字符
              while ((len = in.read(buffer)) != (-1)) {
                  System.out.println(new String(buffer,0,len));
              }
              
                  //每次读12个字符
              while ((len = in.read(buffer,0,12)) != (-1)) {
                  System.out.println(new String(buffer,0,len));
              }
              //4.关闭流资源
              in.close();
          }
      }
      
    • 用字符流完成文件的复制

      public class CopeCharText {
          public static void main(String[] args) throws IOException {
              //1.创建源和目标
              File source = new File("src/hello.txt");
              File target = new File("src/hello1.txt");
      
              //2.创建流对象
              Reader in = new FileReader(source);
              Writer out = new FileWriter(target);
      
              //3.读取和写入操作
              int len;//表示已经读取了多少个字节,如果是 -1,表示已经读取到文件的末尾
              char[] buffer = new char[12];//创建一个容量为 12 的字符数组,存储已经读取的数据
              while ((len = in.read(buffer))!=(-1)){
                  out.write(buffer,0,len);
              }
      
              //4.关闭流资源
              in.close();
              out.close();
          }
      }
      

6. 包装流

包装流隐藏了底层节点流的差异,并对外提供了更方便的输入\输出功能,让我们只关心这个高级流的操作

使用包装流包装了节点流,程序直接操作包装流,而底层还是节点流和IO设备操作

关闭包装流的时候,只需要关闭包装流即可

img
  • 缓冲流

    是一个包装流,目的是缓存作用,加快读取和写入数据的速度。

    • 字节缓冲流:BufferedInputStream、BufferedOutputStream

    • 字符缓冲流:BufferedReader、BufferedWriter

    • 没有缓冲流要实现文件拷贝 字节流 字符流

    • 字节缓冲流 BufferedInputStream、BufferedOutputStream

      通常字节流传输中文会出现乱码,在输入输出流中间包装一层缓冲流可以避免中文乱码

      image-20201122211056527
      public class BufferedInputStreamDemo {
          public static void main(String[] args) throws IOException {
              //1.创建源
              File source = new File("src/hello.txt");
              File target = new File("src/hello1.txt");
      
              //2.创建流对象、包装
              InputStream ins = new BufferedInputStream(new FileInputStream(source));
              OutputStream outs = new BufferedOutputStream(new FileOutputStream(target));
      
              //3.读取操作
              byte[] buffer = new byte[1024];
              int len;
              while ((len = ins.read(buffer,0,1024)) != (-1)) {
                  outs.write(buffer,0,len);
              }
      
              //4.关闭io
              in.close();
              out.close();
          }
      }
      
    • 字符缓冲流 BufferedReader、BufferedWriter
      public class BufferedReaderDemo {
          public static void main(String[] args) throws IOException {
              //1. 创建源和目标
              File source = new File("src/hello.txt");
              File target = new File("src/hello1.txt");
      
              //2. 创建流对象
              Reader in = new FileReader(source);
              Writer out = new FileWriter(target);
                  //包装
              Reader rd = new BufferedReader(in);
              Writer wt = new BufferedWriter(out);
      
              //3. 读取和写入操作
              char[] buffer = new char[1024];
              int len = -1;
              while ((len = rd.read(buffer,0,1024)) != (-1)) {
                  wt.write(buffer);
              }
      
              //4. 关闭流资源
              rd.close();
              wt.close();
      
          }
      }
      
  • 转换流

    InputStreamReader:把字节输入流转换为字符输入流
    OutputStreamWriter:把字节输出流转换为字符输出流
    img

    public class InputStreamReaderDemo {
        public static void main(String[] args) throws IOException {
            //1. 创建源和目标
            File source = new File("src/hello.txt");
            File target = new File("src/helllo1.txt");
    
            //2. 创建流对象
            InputStream in = new FileInputStream(source);
            OutputStream out = new FileOutputStream(target);
                //包装
            Reader rd = new InputStreamReader(in);
            Writer wt = new OutputStreamWriter(out);
    
            //3. 读取和写入操作
            char[] buffer = new char[1024];
            int count = 0;
            int len;
            while ((len = rd.read(buffer)) != (-1)) {
                wt.write(buffer,0,1024);
            }
    
            //4. 关闭流资源
            rd.close();
            wt.close();
        }
    }
    
  • 内存流

    把数据先临时存在数组中,也就是内存中。所以关闭内存流是无效的,关闭后还是可以调用这个类的方法。底层源码的 close()是一个空方法,因此不关闭也没事

    • 字节内存流:ByteArrayOutputStream 、ByteArrayInputStream
      public class ByteArrayOutputStreamDemo {
          public static void main(String[] args) throws IOException {
              //ByteArrayOutputStream
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              baos.write("hello".getBytes());
                  //临时存储
              byte[] temp = baos.toByteArray();
              System.out.println(new String(temp));
      
              //ByteArrayInputStream
              ByteArrayInputStream bais = new ByteArrayInputStream(temp);
              
              byte[] buffer = new byte[10];
              int len = -1;
              while ((len = bais.read(buffer)) != (-1)) {
                  System.out.println(new String(buffer));
              }
              
          }
      }
      
    • 字符内存流:CharArrayReader、CharArrayWriter
      public class CharArrayReaderDemo {
          public static void main(String[] args) throws IOException {
              //CharArrayWriter
              CharArrayWriter caw = new CharArrayWriter();
              caw.write("hello");
              caw.write("哈哈哈");
                  //  返回内存数据的副本
              char[] temp = caw.toCharArray();
              System.out.println(new String(temp));
      
              //CharArrayReader
              CharArrayReader car = new CharArrayReader(temp);
              char[] buffer = new char[10];
              int len = -1;
              while ((len = car.read(buffer)) != (-1)) {
                  System.out.println(new String(buffer));
              }
          }
      }
      
    • 字符串流:StringReader,StringWriter

      把数据临时存储到字符串中

      public class StringReaderDemo {
          public static void main(String[] args) throws IOException {
              //StringWriter
              StringWriter sw = new StringWriter();
              sw.write("ABCD");
              sw.write("春暖花开");
              System.out.println(sw.toString());//底层采用StringBuffer拼接
      
              //StringReader
              StringReader sr = new StringReader(sw.toString());
              char[] buffer = new char[10];
              int len = -1;
              while ((len = sr.read(buffer)) != (-1)) {
                  System.out.println(new String(buffer,0,len));
              }
      
          }
      }
      
  • 合并流/顺序流

    读取的时候是先读第一个,读完了在读下面一个流。

    public class SequenceInputStreamDemo {
        public static void main(String[] args) throws IOException {
    
            //创建流对象
            InputStream in1 = new FileInputStream("src/hello.txt");//helloworld
            InputStream in2 = new FileInputStream("src/test.txt");//test
                //包装
            SequenceInputStream seqin = new SequenceInputStream(in1, in2);
    
            //读取操作
            byte[] buffer = new byte[10];
            int len = -1;
            while ((len = seqin.read(buffer))!=(-1)) {
                System.out.println(new String(buffer,0,len));
            }
    
            //关闭流资源
            seqin.close();
    
        }
    }
    /*
    helloworld
    test
    */
    

7. 总结

  • 字节流
    • buffer为byte数组
  • 字符流
    • buffer为char数组
posted @ 2020-11-22 19:13  球球z  阅读(69)  评论(0)    收藏  举报