java基础学习笔记(五)_IO流

  1. IO流的基本概念
    1. 流的原理
      1) Java 程序中,对于数据的输入 / 输出操作以“流” (stream)方式进行;
      2) J2SDK 提供了各种各样的“流”类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据。
      3) Java 的流类型一般位于 java.io 包中
    2. 流的概念
      1) data source. 提供原始数据的原始媒介。常见的:数据库、文件、其他程序、内存、网络连接、IO 设备。
      2) 数据源就像水箱,流就像水管中流着的水流,程序就是我们最终的用户。 流是一个抽象、动态的概念,是一连串
      连续动态的数据集合。
  2. 流的细分和体系-四大抽象类
    1. 流的分类
      流的方向:
      1) 输入流:数据源到程序 (InputStream Reader 读进来 )
      2) 输出流:程序到目的地 (OutPutStream Writer 写出去 )
      处理数据单元:
      1) 字节流:按照字节读取数据 (InputStream OutputStream)
      2) 字符流:按照字符读取数据 (Reader 、Writer)
      注意: 输入输出是相对于程序而言,而不是相对于源和目标而言
      功能不同:
      1) 节点流:可以直接从数据源或目的地读写数据。
      2) 处理流 ( 包装流 ) :不直接连接到数据源或目的地,是其他流进行封装。目的主要是简化操作和提高性能.
      节点流和处理流的关系:
      1) 节点流处于 io 操作的第一线,所有操作必须通过他们进行;
      2) 处理流可以对其他流进行处理(提高效率或操作灵活性).
    2. 流的体系
      1) InputStream OutputStream
      Java 语言中最基本的两个字节输入输出类。
      其他所有字节输入输出流类都继承自这两个基类。
      这两个类都是抽象类,不能创建它们的实例,只能使用它们的子类.                                                                                2) Reader 和 Writer
      Java 语言中最基本的两个字符输入输出类。
      其他所有字符输入输出流类都继承自这两个基类。
      这两个类都是抽象类,不能创建它们的实例,只能使用它们的子类.
  3. 文件字节流
    1. FileInputStream/FileOutputStream
      使用 FileInputStream 读取文件内容
      1) abstract int read( );
      2) int read( byte b[ ] );
      3) int read( byte b[ ], int off, int len );
      4) int available( );
      5) close( );
      使用 FileOutputStream 写内容到文件
      1) abstract void write( int b );
      2) void write( byte b[ ] );
      3) void write( byte b[ ], int off, int len );
      4) void flush( );
      5) void close( );
      public class TestFileInputStream {
          public static void main(String[] args) throws Exception{
              //(1)数据源与程序之间搭建管道
              FileInputStream fileInputStream=new FileInputStream(new File("f:/a.txt"));
              //(2)从数据源开始向程序中读数据
              int count=fileInputStream.available();
              System.out.println(count);
              //中转站比较小,一次读一个字节
              System.out.println(fileInputStream.read());//读了一个字节
              System.out.println(fileInputStream.available());//估算还要读多少字节
              int buf=0;
              while ((buf=fileInputStream.read())!=-1){
                  System.out.println((char)buf);//读出的是数字,要进行强制类型转换
              }
              //(3)关闭流
              fileInputStream.close();
          }
      }
      public class TestFileInputStream2 {
          public static void main(String[] args) throws IOException {
              //(1)搭管道
              FileInputStream fileInputStream=new FileInputStream("f:/a.txt");
              //(2)要建一个大一点的中转站?这样的话只访问一次磁盘,无参read()访问好几次
              byte[] bytes=new byte[1024];
              int len=0;
              while((len=fileInputStream.read(bytes))!=-1){
                  System.out.println(new String(bytes,0,len));
              }
              //(3)关闭流
              fileInputStream.close();
          }
      }
      public class TestFileOutputStream {
          public static void main(String[] args) {
              FileOutputStream fileOutputStream=null;
              try{
                  fileOutputStream=new FileOutputStream("f:/a.txt",true);//true,对文件原来内容进行追加
                 // fileOutputStream.write(97);
                  byte[] bytes="helloweiwei".getBytes();
                  fileOutputStream.write(bytes);
              }catch (Exception e){
                  e.printStackTrace();
              }finally {
                  try{
                      if(fileOutputStream!=null){
                          fileOutputStream.close();
                      }
                  }catch(Exception e){
                      e.printStackTrace();
                  }
              }
          }
      }
      

       

  4. 使用字节流实现文件复制
    1. 文件复制的原理

    2. 文件复制的源码
      public class TestIOStream {
          public static void main(String[] args) {
              FileInputStream fileInputStream=null;
              FileOutputStream fileOutputStream=null;
              try{
                  fileInputStream=new FileInputStream("f:/a.txt");
                  fileOutputStream=new FileOutputStream("f:/b.txt");
                  byte[] b1=new byte[1024];
                  int num;
                  while((num=fileInputStream.read(b1))!=-1){
                      System.out.println(new String(b1,0,num));
                  }
                  fileOutputStream.write(b1);
              }catch (Exception e){
                  e.printStackTrace();
              }finally {
                  try{
                      if(fileInputStream!=null){
                          fileInputStream.close();
                      }
                      if(fileOutputStream!=null){
                          fileOutputStream.close();
                      }
                  }catch (Exception e){
                      e.printStackTrace();
                  }
              }
          }
      }
  5. 文件字符流
    1. Reader/Writer
      使用 Reader 读取文件内容
      1) int read( );
      2) int read( char [ ]cbuf );
      3) int read( char [ ]cbuf, int off, int len );
      4) int available( );
      5) close( );
      使用 Writer 写内容到文件
      1) void write( int c );
      2) void write( char[]cbuf);
      3) abstract void write( char [ ]cbuf, int off, int len );
      4) void write(String str);
      5) abstract void flush( );
      6) void close( );
      public class TestFileReader {
          public static void main(String[] args) throws IOException {
              FileReader fileReader=null;
              try{
                  fileReader=new FileReader("f:a.txt");
                  char[] b =new char[1024];
                  int i=0;
                  while((i=fileReader.read(b))!=-1){
                      System.out.println(new String(b,0,i));
                  }
              }catch (Exception e){
                  e.printStackTrace();
              }finally {
                  fileReader.close();
              }
          }
      }
      
      public class TestFileWriter {
          public static void main(String[] args) {
              FileWriter fileWriter=null;
              try{
                  fileWriter=new FileWriter("f:/b.txt");
                  fileWriter.write("你好吗");//写到了缓冲区中
                  fileWriter.flush();
              }catch (Exception e){
                  e.printStackTrace();
              }finally {
                  try{
                      if(fileWriter!=null){
                          fileWriter.close();
                      }
                  }catch (Exception e){
                      e.printStackTrace();
                  }
              }
          }
      }
      

  6. 缓冲字节流 _ 缓冲字符流
    1. 缓存字节流
      BufferedInputStream BufferedOutputStream
      FileInputStream FileOutputStream 是节点流
      BufferedInputStream BufferedOutputStream 是处理流(包装流)
      1) 读文件和写文件都使用了缓冲区,减少了读写次数,从而提高了效率
      2) 当创建这两个缓冲流的对象时时,会创建了内部缓冲数组,缺省使用 32 字节大小的缓冲区 .
      3) 当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区
      4) 当写入数据时,首先写入缓冲区,当缓冲区满时,其中的数据写入所连接的输出流。使用方法 flush() 可以强制将缓
      冲区的内容全部写入输出流
      5) 关闭流的顺序和打开流的顺序相反 .只要关闭高层流即可,关闭高层流其实关闭的底层节点流
      6) Flush 的使用:手动将 buffer 中内容写入文件
      public class TestBufferdInputStream {
          public static void main(String[] args) throws Exception{
              //数据源
              FileInputStream fis=new FileInputStream("f:/a.txt");
              FileOutputStream fos=new FileOutputStream("f:/d.txt");
              BufferedInputStream bis=new BufferedInputStream(fis);
              BufferedOutputStream bos=new BufferedOutputStream(fos);
              //中转站
              int len;
              byte[] bytes=new byte[1024];
              long start=System.currentTimeMillis();
              while((len=bis.read(bytes))!=-1){
                  bos.write(bytes);
                  bos.flush();
              }
              long end=System.currentTimeMillis();
              System.out.println(end-start);
              //关闭流
              bis.close();
              bos.close();
          }
      }

       

    2. 缓存字符流
      BufferedReader
      readLine() 读取一个文本行的数据
      BufferedWriter
      newLine() ;写入一个行分隔符。
      使用缓冲字符流是复制文本文件常用的方式
      public class TestBufferReader {
          public static void main(String[] args) throws Exception{
              //先找数据源
              FileReader fr=new FileReader("f:a.txt");
              FileWriter fs=new FileWriter("f:b.txt");
              BufferedReader br=new BufferedReader(fr);
              BufferedWriter bw=new BufferedWriter(fs);
              String line=null;//用于存储读到的字符串
              while((line=br.readLine())!=null){
                  bw.write(line);
                  bw.newLine();
                  bw.flush();
              }
              if(br!=null){
                  br.close();
              }
              if(bw!=null){
                  bw.close();
              }
          }
      }

       

  7. 转换流
    1. InputStreamReader 和 OutputStreamWriter
      处理流
      用于将字节流转化成字符流,字符流与字节流之间的桥梁
      InputStreamReader 的作用是把 InputStream 转换成 Reader
      OutputStreamWriter 的作用是把 OutputStream 转换成 Writer
      存在将字节流转换成字符流的转换流,因为字符流操作文本更简单
      不存在把字符流转换成字节流的转换流,因为没有必要
      System.in 代表标准输入,即键盘输入,是 InputStream 的实例
      public class TestInputStreamReader2 {
          public static void main(String[] args) throws IOException {
              //任务需求,从键盘获取文件,写入磁盘文件
              //1.数据源是标准的输入设备,键盘System.in
              InputStream is=System.in;
              //2.需要使用转换流,转成字符流
              InputStreamReader isr=new InputStreamReader(is,"gbk");
              //3.提高读取效率
              BufferedReader br=new BufferedReader(isr);
              //4.提高写入效率
              BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("F:/a.txt"),"gbk"));
              //5.写入磁盘
              String line=null;
              while (!"over".equals(line=br.readLine())){
                  bw.write(line);
                  bw.newLine();
                  bw.flush();
              }
              //6.关闭流
              bw.close();
              br.close();
          }
      }

       

  8. 打印流
    1. PrintStream
      1) PrintStream 提供了一系列的 print() println() ,可以实现将基本数据类型格式化成字符串输出。对象类型将先调用
      toString() ,然后输出该方法返回的字符串
      2) System.out 就是 PrintStream 的一个实例,代表显示器
      3) System.err 也是 PrintStream 的一个实例,代表显示器
      4) PrintStream 的输出功能非常强大,通常需要输出文本内容,都可以将输出流包装成 PrintStream 后进行输出
      5) PrintStream 的方法都不抛出 IOException
    2. PrintWriter
      1) PrintStream 的对应字符流,功能相同,方法对应。
      2) PrintWriter 的方法也不抛出 IOException
      3) 复制文件时可以使用 PrintWriter 代替 BufferedWriter 完成,更简单
      public class TestPrintSteam {
          public static void main(String[] args) throws Exception {
             // PrintStream ps=System.out;
             // PrintStream ps=System.err;
            //  PrintStream ps=new PrintStream(new FileOutputStream("f:/a.txt"));
              PrintWriter ps=new PrintWriter(new FileOutputStream("f:/a.txt"));
              //无需类型转换,自动转成String类型
              ps.println(123);
              ps.println(true);
              ps.flush();
              ps.close();
              //只能写入字符串
              BufferedWriter bw=new BufferedWriter(new FileWriter("f:/a.txt"));
             //报错 bw.write(98.5);
          }
      }
      
  9. 数据流
    1. DataInputStream 和 DataOutputStream
      1) 提供了可以存取所有 Java 基础类型数据(如:int,double等)和 String 的方法。
      2) 处理流,只针对字节流,二进制文件
      3) 输入流链和输出流链
      4) 注意:只要关闭上层流即可
      public class TestDataInputStream {
          public static void main(String[] args) throws IOException {
              write();
          }
          public static void read() throws IOException{
              FileInputStream fis=new FileInputStream("f:/a.txt");
              BufferedInputStream bis=new BufferedInputStream(fis);
              DataInputStream dis=new DataInputStream(bis);
              //读数据的顺序要和写数据的顺序完全一致
              dis.readInt();
              dis.readUTF();
              dis.readBoolean();
              if(dis!=null){
                  dis.close();
              }
          }
          public static void write() throws IOException{
              //1.目的地
              FileOutputStream fos=new FileOutputStream("f:/a.txt");
              //2.缓存流,提高效率
              BufferedOutputStream bos=new BufferedOutputStream(fos);
              //3.数据流,增加对java基本类型和String的处理
              DataOutputStream dos=new DataOutputStream(bos);
              //4.写入数据
              dos.writeInt(98);
              dos.writeUTF("微微");
              dos.writeBoolean(true);
              //5.关闭上层流
              if(dos!=null){
                  dos.close();
              }
          }
      }
      

       

  10. 对象流
    1. 对象序列化 (Serialization)
      ObjectOutputStream -> 序列化 -> 写对象,将对象以“二进制/ 字节”的形式写到(文件)
      ObjectInputStream -> 反序列化-> 读对象
      Java 对象转换成字节序列( IO 字节流)
      对象反序列化 (DeSerialization)
      从字节序列中恢复 Java 对象
    2. 为什么序列化
      序列化以后的对象可以保存到磁盘上,也可以在网络上传输,使得不同的计算机可以共享对象. (序列化的字节序列是
      平台无关的)
    3. 对象序列化的条件
      只有实现了 Serializable 接口的类的对象才可以被序列化。Serializable 接口中没有任何的方法,实现该接口的类不需要实现额外的方法。如果对象的属性是对象,属性对应类也必须实现 Serializable接口
    4. 如何实现序列化
      创建 ObjectOutputStream 对象
      调用 writeObject() 输出对象
    5. 如何实现反序列化
      创建 ObjectInputStream 对象
      调用 readObject() 读取对象
      public class TestObjectOutputStream {
          public static void main(String[] args) throws IOException, ClassNotFoundException {
              write();
              read();
          }
          public static void  write() throws IOException{
              ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("f:/a.txt"));
              oos.writeObject(new Person("marry",20));
              if(oos!=null){
                  oos.close();
              }
          }
          public static void read() throws IOException, ClassNotFoundException {
              ObjectInputStream ois=new ObjectInputStream(new FileInputStream("f:/a.txt"));
              Person person = (Person)ois.readObject();
              if(ois!=null){
                  ois.close();
              }
          }
      }
  11. 序列化与反序列化
    1. ​​​​​​​序列化与反序列化
      1) 序列化能保存的元素
      a) 只能保存对象的非静态成员变量
      b) 不能保存任何成员方法和静态的成员变量
      c) 不保存 transient 成员变量
      d) 如果一个对象的成员变量是一个对象,这个对象的成员变量也会保存
      e) 串行化保存的只是变量的值,对于变量的任何修饰符,都不能保存
      2) 使用对象流把一个对象写到文件时不仅保证该对象是序列化的,而且该对象的成员对象也必须是可序列化的。
      3) 如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个
      NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
    2. 对象序列化注意事项
      1) 同一个对象多次序列化的处理
      a) 所有保存到磁盘中的对象都有一个序列化编号
      b) 序列化一个对象中,首先检查该对象是否已经序列化过
      c) 如果没有,进行序列化
      d) 如果已经序列化,将不再重新序列化,而是输出编号即可
      2) 如果不希望某些属性(敏感)序列化,或不希望出现递归序列
      a) 为属性添加 transient 关键字(完成排除在序列化之外)
      b) 自定义序列化(不仅可以决定哪些属性不参与序列化,还可以定义属性具体如何序列化)
      3) 序列化版本不兼容
      a) 修改了实例属性后 , 会影响版本号,从而导致反序列化不成功
      b) 解 决 方 案 : 为 Java 对 象 指 定 序 列 化 版 本 号serialVersionUID
  12. 文件夹的复制
    字节流 ,字符流
    BufferedInputStream,BufferedOutputStream
    FileInputStream,FileOutputStream
    问题分解
    (1) 复制一个文件
    (2) 指定目录下的所有文件
    (3) 指定目录下的所有文件及子目录下的所有文件
    public class CopyDir {
        public static void main(String[] args) throws Exception {
            File src=new File("d:/test");
            File dest=new File("f:/test");
            copyDir(src,dest);
        }
        public static void copyDir(File src,File dest) throws Exception{
            if(!dest.exists()){
                dest.mkdir();
            }
            File[] files=src.listFiles();
            for(File file:files){
                if(file.isFile()){
                    copyFile(new File(src+"\\"+file.getName()),new File(dest+"\\"+file.getName()));
                }
                else{
                    copyDir(new File(src+"\\"+file.getName()),new File(dest+"\\"+file.getName()));
                }
            }
        }
        public static void copyFile(File src, File dest) throws Exception{
            FileOutputStream fileOutputStream=new FileOutputStream(dest);
            BufferedOutputStream bos=new BufferedOutputStream(fileOutputStream);
            FileInputStream fis=new FileInputStream(src);
            BufferedInputStream bis=new BufferedInputStream(fis);
            byte[] buffer=new byte[1024];
            int len;
            while((len=bis.read(buffer))!=-1){
                bos.write(buffer);
            }
        }
    }
    
  13. 字节数组流
    1) 数据源或目的地为:字节数组,将各种类型的数据转成字节数组进行传输
    2) 只有字节数组流,没有字符数组流,两台电脑进行数据传输是传递字节,不是字符
    3) 节点流
    public class Test {
        public static void main(String[] args) throws IOException {
          byte[] buf=  write();
          read(buf);
        }
        public static byte[] write() throws IOException {
            //创建字节数组流
            ByteArrayOutputStream baos=new ByteArrayOutputStream();//创建字节数组流对象,目的地是字节数组,底层创建一个32的字节数组
            ObjectOutputStream oos=new ObjectOutputStream(baos);
            oos.writeBoolean(true);
            oos.writeInt(98);
            oos.close();
            return baos.toByteArray();
        }
        public static void read(byte[] buf) throws IOException {
            ByteArrayInputStream bis=new ByteArrayInputStream(buf);
            ObjectInputStream ois=new ObjectInputStream(bis);
            ois.readBoolean();
            ois.readInt();
            if(ois!=null){
                ois.close();
            }
        }
    }
    
  14. 设计模式-装饰器模式
    职责 : 动态的为一个对象增加新的功能
    装饰模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能 。使用对象的关联关系代替继承关
    系,更加灵活,同时避免类型体系的快速膨胀。
    实现细节:
    1 ) 抽象构件角色 ICar
    2 ) 具体的构件角色 Car
    3 ) 装饰器角色 SuperCar
    4 ) 具体的装饰器角色 FlyCar WaterCar AICar
    public interface ICar {
        public void move();
    }
    public class Car implements ICar {
        @Override
        public void move() {
            System.out.println("普通汽车在公路上行驶");
        }
    }
    public class SuperCar implements ICar {
        private ICar icar;
        public SuperCar(ICar iCar){
            this.icar=iCar;
        }
        @Override
        public void move() {
            icar.move();
        }
    }
    public class FlyCar extends SuperCar {
        public FlyCar(ICar car){
            super(car);
        }
        @Override
        public void move() {
            super.move();
            fly();
        }
        public void fly(){
            System.out.println("汽车可以飞行:因为有了翅膀");
        }
    }
    
    public class WaterCar extends SuperCar {
        public WaterCar(ICar car){
            super(car);
        }
        @Override
        public void move() {
            super.move();
            this.water();
        }
        public void water(){
            System.out.println("汽车可以潜水:因为汽车装了潜水轮");
        }
    }
    public class AICar extends SuperCar {
        public AICar(ICar car){
            super(car);
        }
        @Override
        public void move() {
            super.move();
            this.aotodrive();
        }
        public void aotodrive(){
            System.out.println("可以自动行驶");
        }
    }
    public class Test01 {
        public static void main(String[] args) {
           /* ICar car=new Car();
            car.move();
            SuperCar car1=new FlyCar(car);
            car1.move();
            SuperCar car2=new WaterCar(car);
            car2.move();
            SuperCar car3=new AICar(car);
            car3.move();*/
            ICar icar=new Car();
            FlyCar flyCar=new FlyCar(icar);
            WaterCar waterCar=new WaterCar(flyCar);
            AICar aiCar=new AICar(waterCar);
            aiCar.move();
            //各种组合
            WaterCar waterCar1=new WaterCar(new FlyCar(new AICar(new Car())));
        }
    }
    优点 :
    1) 扩展对象功能,比继承灵活,不会导致类个数急剧增加
    2) 可以对一个对象进行多次装饰,创建出不同行为的组合,得到功能更加大的对象
    3) 具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类
    缺点:
    1) 产生很多小对象。大量小对象占据内存,一定程序上影响性能
    2) 装饰模式易于出错,调试排查比较麻烦
    IO 流实现细节
    (1) 抽象构件角色 InputStream,OutputStream,Reader,Writer
    (2) 具体构件角色 FileInputStream,FileOutputStream
    (3) 装饰器角色 FilterInputStream,FilterOutputStream持有一个抽象构件的引用
    (4) 具体装饰角色 BufferedInputStream,BufferedOutputStream 等
  15. IO流体系总结
    (1) 字节流 :InputStream,OutputStream
    (2) 字符流 :Reader ,Writer
    (3) 数据流 :DataInputStream,DataOutputStream
    (4) 对象流 :ObjectInputStream,ObjectOutputStream
    (5) 缓冲流 :BufferedInputStream,BufferedOutputStream BufferedReader,BufferedWriter
    (6) 转换流 :InputStreamReader,OutputStreamWriter
    (7) 数组流 : ByteArrayInputStream,ByteArrayOutputStream
    (8) 打印流 :PrintStream,PrintWriter
  16. Apache IOUtils的使用_Apache FileUtils的使用
    1. ​​​​​​​IOUtils 与 FileUtils
      Commons IO apache 的一个开源的工具包 , 封装了 IO 操作的相关类, 使用 Commons IO 可以很方便的读写文件 ,
      (1) FileUtils 中提供了许多设计文件操作的 已封装好的方法。
      (2) IOUtils 则是提供了读写文件的方法
    2. IOUtils 工具类操作的相关方法
      (1)String IOUtils.toString(InputStream input) 传入输入流对象返回字符串
    3. FileUtils 工具类操作的相关方法
      (1)String FileUtils.readFileToString(File file,String encoding)
      FileUtils.writeStringToFile(File file,String data,String encoding)读写文
      (2)FileUtils.copyFile(File srcFile,File destFile) 复制文件
      (3)FileUtils.copyURLToFile(URL source,File destination) 复制 url 对象到指定文件
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值