java I/O 这篇就够了

java I/O

文件对象

文件和文件夹都是用File来表示

  • 创建文件对象

    package file;
      
    import java.io.File;
      
    public class TestFile {
          
          
      
        public static void main(String[] args) {
          
          
            // 绝对路径
            File f1 = new File("d:/LOLFolder");
            System.out.println("f1的绝对路径:" + f1.getAbsolutePath());
            // 相对路径,相对于工作目录,如果在eclipse中,就是项目目录
            File f2 = new File("LOL.exe");
            System.out.println("f2的绝对路径:" + f2.getAbsolutePath());
      
            // 把f1作为父目录创建文件对象
            File f3 = new File(f1, "LOL.exe");
      
            System.out.println("f3的绝对路径:" + f3.getAbsolutePath());
        }
    }
    

    结果如下

在这里插入图片描述

字节流

以字节流的形式读取和输出,实现复制内容的效果

因为内容是以字节的形式传输的,所以就算不是文本文件,诸如.exe文件都可以通过这种方式实现数据传输。

package top.faroz.file;

import java.io.*;

/**
 * @ClassName FileDemo6
 * @Description TODO
 * @Author FARO_Z
 * @Date 2020/8/19 5:39 下午
 * @Version 1.0
 **/
public class FileDemo6 {
    
    
    public static void main(String[] args) {
    
    
        File inFile = new File("/Users/faro_z/Documents/hahaha.txt");
        File outFile = new File("/Users/faro_z/Documents/wdnmd.txt");
        byte[] bytes = new byte[30];
        try {
    
    
            FileInputStream fileInputStream = new FileInputStream(inFile);
            /**
             * 通过read()方法将文件内容的字节流读入byte[] 数组
             */
            fileInputStream.read(bytes);
            fileInputStream.close();
            FileOutputStream fileOutputStream = new FileOutputStream(outFile);
            /**
             * 然后在通过write方法,将字节数组中的内容写到新的文件 wdnmd.txt
             * 如果wdnmd.txt不存在。会自动创建一个
             */
            fileOutputStream.write(bytes);
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

  • 关闭流的方式

    1. 在try中关闭

      在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
      如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用

      package stream;
       
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
       
      public class TestStream {
              
              
       
          public static void main(String[] args) {
              
              
              try {
              
              
                  File f = new File("d:/lol.txt");
                  FileInputStream fis = new FileInputStream(f);
                  byte[] all = new byte[(int) f.length()];
                  fis.read(all);
                  for (byte b : all) {
              
              
                      System.out.println(b);
                  }
                  // 在try 里关闭流
                  fis.close();
              } catch (IOException e) {
              
              
                  e.printStackTrace();
              }
       
          }
      }
      
    2. 在finally中关闭

      这是标准的关闭流的方式
      \1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
      \2. 在finally关闭之前,要先判断该引用是否为空
      \3. 关闭的时候,需要再一次进行try catch处理

      这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~

      package top.faroz.file;
      
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      import java.io.IOException;
      
      /**
       * @ClassName FileDemo7
       * @Description 试试用finally关闭流的方法
       * @Author FARO_Z
       * @Date 2020/8/24 10:24 上午
       * @Version 1.0
       **/
      public class FileDemo7 {
              
              
          public static void main(String[] args) {
              
              
              File f1 = new File("/Users/faro_z/Documents/testFile1.txt");
              FileInputStream fis1=null;
              try {
              
              
                  byte[] bytes = new byte[(int) f1.length()];
                  fis1 = new FileInputStream(f1);
                  fis1.read(bytes);
                  for (byte aByte : bytes) {
              
              
                      System.out.println(aByte);
                  }
              } catch (FileNotFoundException e) {
              
              
                  e.printStackTrace();
              } catch (IOException e) {
              
              
                  e.printStackTrace();
              } finally {
              
              
                  if (fis1!=null) {
              
              
                      try {
              
              
                          fis1.close();
                      } catch (IOException e) {
              
              
                          e.printStackTrace();
                      }
                  }
              }
          }
      }
      
    3. 使用try()的方式

      把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
      这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术

      所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。

      代码比较复制代码

      package stream;
        
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
        
      public class TestStream {
              
              
        
          public static void main(String[] args) {
              
              
              File f = new File("d:/lol.txt");
        
              //把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
              try (FileInputStream fis = new FileInputStream(f)) {
              
              
                  byte[] all = new byte[(int) f.length()];
                  fis.read(all);
                  for (byte b : all) {
              
              
                      System.out.println(b);
                  }
              } catch (IOException e) {
              
              
                  e.printStackTrace();
              }
        
          }
      }
      

字符流

  1. 使用字符流读取文件

    FileReader 是Reader子类,以FileReader 为例进行文件读取

    package top.faroz.file;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.Arrays;
    
    /**
     * @ClassName FileDemo8
     * @Description 字符流读取文件
     * 使用try()的方式关闭资源
     * @Author FARO_Z
     * @Date 2020/8/24 10:39 上午
     * @Version 1.0
     **/
    public class FileDemo8 {
          
          
        public static void main(String[] args) {
          
          
            File f1 = new File("/Users/faro_z/Documents/testFile1.txt");
            try(FileReader fr1 = new FileReader(f1)) {
          
          
                final char[] chars = new char[(int) f1.length()];
                /**
                 * 使用read方法将字符流中的内容读取到字符数组
                 */
                fr1.read(chars);
    
                String s=String.valueOf(chars);
                System.out.println(s);
            } catch (FileNotFoundException e) {
          
          
                e.printStackTrace();
            } catch (IOException e) {
          
          
                e.printStackTrace();
            }
        }
    }
    
    1. 使用字符流写文件

      使用类FileWriter,和上面的读文件操作差不多,这里不再赘述

      package stream;
        
      import java.io.File;
      import java.io.FileWriter;
      import java.io.IOException;
        
      public class TestStream {
              
              
        
          public static void main(String[] args) {
              
              
              // 准备文件lol2.txt
              File f = new File("d:/lol2.txt");
              // 创建基于文件的Writer
              try (FileWriter fr = new FileWriter(f)) {
              
              
                  // 以字符流的形式把数据写入到文件中
                  String data="abcdefg1234567890";
                  char[] cs = data.toCharArray();
                  fr.write(cs);
        
              } catch (IOException e) {
              
              
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
        
          }
      }
      

字符缓存流

  • 使用缓存流的原因

    以介质是硬盘为例,字节流和字符流的弊端
    在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。

    为了解决以上弊端,采用缓存流。
    缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。

    就好比吃饭,不用缓存就是每吃一口都到锅里去铲用缓存就是先把饭盛到碗里,碗里的吃完了,再到锅里去铲

    缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作

    1. 使用缓存流读取数据

    缓存字符输入流BufferedReader,可以一次读取一行数据

    package stream;
      
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
      
    public class TestStream {
          
          
      
        public static void main(String[] args) {
          
          
            // 准备文件lol.txt其中的内容是
            // garen kill teemo
            // teemo revive after 1 minutes
            // teemo try to garen, but killed again
            File f = new File("d:/lol.txt");
            // 创建文件字符流
            // 缓存流必须建立在一个存在的流的基础上
            try (
                    FileReader fr = new FileReader(f);//这里必须要注意
              			//缓存流一定要建立在一个存在的流之上
                    BufferedReader br = new BufferedReader(fr);
                )
            {
          
          
                while (true) {
          
          
                    // 一次读一行
                    String line = br.readLine();
                    if (null == line)
                        break;
                    System.out.println(line);
                }
            } catch (IOException e) {
          
          
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
      
        }
    }
    
    1. 使用缓存流写出数据

    PrintWriter 缓存字符输出流, 可以一次写出一行数据
    这里不使用BufferedWriter,原因如下:

    ****BufferedWriter****:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。如果要对字节流操作,则使用BufferedInputStream。

    ****PrintWriter****:向文本输出流打印对象的格式化表示形式(Prints formatted representations of objects to a text-output stream)。PrintWriter相对于BufferedWriter的好处在于,如果PrintWriter开启了自动刷新,那么当PrintWriter调用println,prinlf或format方法时,输出流中的数据就会自动刷新出去。PrintWriter不但能接收字符流,也能接收字节流。

    package stream;
       
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
       
    public class TestStream {
          
          
       
        public static void main(String[] args) {
          
          
            // 向文件lol2.txt中写入三行语句
            File f = new File("d:/lol2.txt");
              
            try (
                    // 创建文件字符流
                    FileWriter fw = new FileWriter(f);
                    // 缓存流必须建立在一个存在的流的基础上              
                    PrintWriter pw = new PrintWriter(fw);              
            ) {
          
          
                pw.println("garen kill teemo");
                pw.println("teemo revive after 1 minutes");
                pw.println("teemo try to garen, but killed again");
            } catch (IOException e) {
          
          
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
       
        }
    }
    
  • 当然,还有字节缓存流
    分别是BufferedInputStream和BufferedOutputStream
    使用方法和字符缓冲流差不多,这里不再演示

数据流

数据流可以用来进行格式化顺序读写

使用DataInputStream和DataOutputStream

注意: 要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。

下面这个例子体现了数据流在某些方面的便利性
用缓冲流输出两个int类型数字还要使用符号"@"隔开,读取才方便
但是数据流就不需要什么字符分隔,挨个读就好了,这也解释了为什么 要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的

package stream;
       
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
       
public class TestStream {
    
    
    static File f =new File("d:/data.txt");
    static int x = 31;
    static int y = 15;
    public static void main(String[] args) {
    
    
         
        //缓存流方式
        method1();
        //数据流方式
        method2();
    }
  
    private static void method2() {
    
    
        try (
                FileInputStream fis  = new FileInputStream(f);
                DataInputStream dis =new DataInputStream(fis);
                FileOutputStream fos  = new FileOutputStream(f);
                DataOutputStream dos =new DataOutputStream(fos);
                 
        ){
    
    
            dos.writeInt(x);
            dos.writeInt(y);
             
            int x = dis.readInt();
            int y = dis.readInt();
            System.out.printf("使用数据流读取出的x是 %d y是 %d%n",x,y);
             
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
         
    }
 
    private static void method1() {
    
    
         try (
                 FileWriter fw = new FileWriter(f);
                 PrintWriter pw = new PrintWriter(fw);
                 FileReader fr = new FileReader(f);
                 BufferedReader br = new BufferedReader(fr);                
                  
         ) {
    
    
             pw.print(x+"@"+y);
             pw.flush();
             String str = br.readLine();
             String[] ss =str.split("@");
             int x = Integer.parseInt(ss[0]);
             int y = Integer.parseInt(ss[1]);
             System.out.printf("使用缓存流读取出的x是 %d y是 %d%n",x,y);
              
         } catch (IOException e) {
    
    
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
    
    }
 
    private static void read() {
    
    
        File f =new File("d:/data.txt");
        try (
                FileInputStream fis  = new FileInputStream(f);
                DataInputStream dis =new DataInputStream(fis);
        ){
    
    
            boolean b= dis.readBoolean();
            int i = dis.readInt();
            String str = dis.readUTF();
              
            System.out.println("读取到布尔值:"+b);
            System.out.println("读取到整数:"+i);
            System.out.println("读取到字符串:"+str);
  
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
          
    }
  
    private static void write() {
    
    
        File f =new File("d:/data.txt");
        try (
                FileOutputStream fos  = new FileOutputStream(f);
                DataOutputStream dos =new DataOutputStream(fos);
        ){
    
    
            dos.writeBoolean(true);
            dos.writeInt(300);
            dos.writeUTF("123 this is gareen");
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
          
    }
}

对象流

对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘

一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口

这里直接写一个例子

准备一个长度是10,类型是Hero的数组,使用10个Hero对象初始化该数组

然后把该数组序列化到一个文件heros.lol

接着使用ObjectInputStream 读取该文件,并转换为Hero数组,验证该数组中的内容,是否和序列化之前一样

  • Hero类
    注意,这个将要被序列化的Hero类必须实现Serializable接口

    package top.faroz.domain;
    
    import java.io.Serializable;
    
    /**
     * @ClassName Hero
     * @Description TODO
     * @Author FARO_Z
     * @Date 2020/8/26 1:03 上午
     * @Version 1.0
     **/
    public class Hero implements Serializable {
          
          
        private String name;
    
        public Hero(String name) {
          
          
            this.name = name;
        }
    
        public String getName() {
          
          
            return name;
        }
    
        public void setName(String name) {
          
          
            this.name = name;
        }
    }
    
    
  • 主体

package top.faroz.file;

/**
 * @ClassName FileDemo11
 * @Description 对象流的测试
 * @Author FARO_Z
 * @Date 2020/8/26 1:03 上午
 * @Version 1.0
 **/

import top.faroz.domain.Hero;

import java.io.*;

/**
 * 需求:
 * 准备一个长度是10,类型是Hero的数组,使用10个Hero对象初始化该数组
 * 然后把该数组序列化到一个文件heros.lol
 * 接着使用ObjectInputStream 读取该文件,并转换为Hero数组,验证该数组中的内容,是否和序列化之前一样
 */
public class FileDemo11 {
    
    
    public static void main(String[] args) {
    
    
        Hero[] heroes = new Hero[10];
        for (int i = 0; i < 10; i++) {
    
    
            heroes[i]=new Hero("我是第"+i+"号英雄");
        }
        doTest(heroes);
    }

    public static void doTest(Hero[] heros) {
    
    
        File file = new File("/Users/faro_z/Documents/testFile/hero.lol");
        try(FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos)
        ) {
    
    
            oos.writeObject(heros);
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }

        try(FileInputStream fis = new FileInputStream(file);
            ObjectInputStream ois = new ObjectInputStream(fis)
        ) {
    
    
            Hero[] heroes2 = (Hero[]) ois.readObject();
            for (Hero hero : heroes2) {
    
    
                System.out.println(hero.getName());
            }

        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44062380/article/details/108232156