Java基础_IO流

109 阅读6分钟

Java基础—IO流

IO流.png

参考文章

IO流主要的分类方式有以下3种:

  1. 按数据流的方向:输入流、输出流
  2. 按处理数据单位:字节流、字符流
  3. 按功能:节点流、处理流

字节流和字符流的其他区别:

  • 字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件。
  • 字符流一般用于处理纯文本类型的文件,如TXT文件等,但不能处理图像视频等非文本文件。
  • 用一句话说就是:字节流可以处理一切文件,而字符流只能处理纯文本文件。
  • 字节流本身没有缓冲区,缓冲字节流相对于字节流,效率提升非常高。
  • 而字符流本身就带有缓冲区,缓冲字符流相对于字符流效率提升就不是那么大了。

节点流与包装类(处理流)的说明

  • 当一个流的构造方法需要一个流(参数)的时候,这个被传递进来的流叫:节点流
  • 外部负责保证的这个流叫:包装流 或 处理流

输入流与输出流的说明

  • 输入流—输入:数据流向内存
  • 输出流—输出:数据从内存中流出

java.io包下需要掌握的流有16个:

文件专属: File

  • java.io.FileInputstream (掌握)
  • java.io.FileOutputstream (掌握)
  • java.io.FileReader
  • java.io.FileWriter

转换流:(将字节流转换成字符流)

  • java.io.InputstreamReader
  • java.io.OutputstreamWriter

缓冲流专属: Buffered

  • java.io.BufferedReader
  • java.io.BufferedWriter
  • java.io.BufferedInputstream
  • java.io.Bufferedoutputstream

数据流专属: Data

  • java.io.DataInputstream
  • java.io.DataOutputstream

标准输出流: Print

  • java.io.PrintWriter
  • java.io.Printstream

对象专属流: object

  • java.io.objectInputstream (掌握)
  • java.io.Objectoutputstream(掌握)

tip:

  • 在java中只要类名"Stream" 结尾的都是字节流,以"Reader、Writer"结尾的都是字符流

  • 所有的流都实现了 Closeable接口,都有close()方法,都是可以关闭的。 Stream流使用时要开启管道传输(建立通信机制),这个是内存和硬盘之间的通道,用完之后一定要关闭!不然会占用很多资源。

  • 所有的输出流都实现了 Flushable接口,都有flush()方法,都是可刷新的。表示把管道中的剩余未输出的数据,输出到指定位置上。

文件流 File

  • java.io.FileInputstream
  • java.io.FileOutputstream
  • java.io.FileReader
  • java.io.FileWriter

1. 文件字节流 FileInputStream、FileOutputStream

字节流的方式效率较低,不建议使用

FileInputStream方法摘要

image.png

FileOutputStream方法摘要

image.png

FileInputStream、FileOutputStream,实现 '文件拷贝' 功能

public class Copy01 {
   public static void main(String[] args) {
      
      FileInputStream fis = null;
      FileOutputStream fos = null;
      
      /**
       * bytes:存放读取数据的数组
       * readCount:读取的字节数
       */
      byte[] bytes = new byte[1024*1024];
      int readCount=0;
      
      try {
         // 连接管道
         fis = new FileInputStream("xxx\xxx\a.mp4");
         fos = new FileOutputStream("xxx\xxx\b.mp4");
         
         /**
          * readCount:读取到的字节数; 如果没读到数据(读完)则返回-1
          * fis.read(bytes):读取数组大小的数据,并存储到数组中
          */
         while ((readCount=fis.read(bytes))!=-1){
            fos.write(bytes,0,readCount); // 把内存中数组的数据,写入到磁盘
         } 
         fos.flush(); // 输出流最后要刷新
      } catch (Exception e) {
         e.printStackTrace();
      }
      // 不能一起关闭(try),如果其中一个异常,会影响另一个的关闭
      finally {
         if (fis != null) {
            try {
               fis.close();
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
         if(fos!=null){
            try {
               fos.close();
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
      }
   }
}

2. 文件字符流 FileReader、FileWriter

字符流适用于文本文件的读写OutputStreamWriter类其实也是借助FileOutputStream类实现的,故其构造方法是FileOutputStream的对象

FileReader

/**
 * FileReader
 *      文件字符输入流,只读取普通文本
 *      读取文本内容时,比较方便,快捷
 */
public class FileRead01 {
   public static void main(String[] args) {
      FileReader reader = null;
      char[] chars = new char[4]; // 一次读取4个字符
      
      try {
         reader = new FileReader("a.txt");
         int readCount = 0;
         while ((readCount = reader.read(chars)) != -1){
            System.out.print(new String(chars,0,readCount));
         }
      } catch (IOException e) {
         e.printStackTrace();
      } finally {
         if (reader != null){
            try {
               reader.close();
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
      }
   }
}
image.png image.png

FileWriter

tip:文件字符流 可以使用字符数组字符串写入

public class FileWriter01 {
   public static void main(String[] args) {
      FileWriter writer = null;
      try {
         // 如果不加参数`true`,每次写之前会把之前写的清空,再写入这一次的数据
         writer =  new FileWriter("src/main/java/IO/FileReader/a.txt",true);
         // 字符数组
         char[] chars = {'我','是','曼','德'};
         writer.write(chars);
         writer.write('\n'); // 换行
         // 字符串
         String s = "观众老爷,来个点赞!";
         writer.write(s);
         writer.flush();
         
      } catch (IOException e) {
         e.printStackTrace();
      }finally {
         if (writer != null) {
            try {
               writer.close();
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
      }
   }
}
image.png

缓冲流 Buffered

  • java.io.BufferedReader
  • java.io.BufferedWriter
  • java.io.BufferedInputstream
  • java.io.Bufferedoutputstream

缓冲字节流是为高效率而设计的,真正的读写操作还是靠FileOutputStreamFileInputStream,所以其构造方法入参是这两个类的对象也就不奇怪了。

tip:BufferReader 带有缓冲区的字符输入流
使用这个流的时候不需要自定义char数组或者byte数组。自带缓冲

BufferReader方法摘要

image.png

使用BufferReader的readLine()方法 读取文本

tip:br.readLine()方法读取一个文本行,但不带换行符 '\n'

public class BufferReader01 {
   public static void main(String[] args) throws IOException {
      // 当一个流的构造方法需要一个流的时候,这个被传递进来的流叫:节点流
      // 外部负责保证的这个流叫:包装流 或 处理流
      // 像当前这个程序来说:FileReader 就是节点流,BufferedReader就是包装流
      FileReader reader = new FileReader("a.txt");
      BufferedReader br = new BufferedReader(reader);
      
      // 读取第二行
      //String line1 = br.readLine(); // 一次读一行
      //System.out.println(line1);
      
      // 读取第二行
      //String line2 = br.readLine();
      //System.out.println(line2);
      
      String s = null;
      // 循环读取,如果到达行尾则返回null
      // br.readLine()方法读取一个文本行,但不带换行符 '\n'
      while ((s = br.readLine())!=null){
         System.out.println(s);
      }
      
      /**
       * 关闭流
       * 对于包装流来说,只需要关闭最外层的流,里面的节点流会自动关闭,可以看源码
       */
      br.close();
      
   }
}

转换流

  • java.io.InputstreamReader
  • java.io.OutputstreamWriter
BufferedReader(Reader in) 因为缓冲字符流只能接收参数是 字符流类型的参数,
如果当前只有字节流,则可以使用到转换流。有这种需求的可以考虑使用~

tip:为了代码美观就把异常抛给方法了,一般情况不会这么做。
public class BufferedReader02 {
   
   public static void main(String[] args) throws Exception {
      
      /**
       * 1.创建字符流 2.字节流 用转换流转为 字符流,
       * 3.字符流当BufferedReader的参数
       */
      FileInputStream fis = new FileInputStream("a.txt");
      InputStreamReader in = new InputStreamReader(fis);
      BufferedReader br = new BufferedReader(in);
      
      // 合并写法
      //br =  new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));
      
      String line = null;
      while((line = br.readLine())!=null){
         System.out.println(line);
      }
      
      br.close();
   }
}

数据流 (了解即可)

DataInputStream—数据字节输入流

DataOutputStream写的文件,只能使用DataInputStream去读。并且读的时候需要提前知道写入的顺序。读的顺序需要和写的顺序一致。才可以正常取出数据。

标准输出流

  • 标准输出流可以指定位置输出数据,类似于log日志
public class Logger01 {
   public static void log(String msg){
      try {
         // 指向一个日志文件
         PrintStream out = new PrintStream(new FileOutputStream("log.txt", true));
         // 改变输出方向
         System.setOut(out);
         // 日期当前时间
         Date nowTime = new Date();
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
         String strTime = sdf.format(nowTime);
         // 这里的输出 会向指定文件进行输出
         System.out.println(strTime+":"+msg);
         
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      }
   }
}

测试

public class Test {
   public static void main(String[] args) {
      Logger01.log("调用了xxx方法");
      Logger01.log("调用了xxx方法,出现异常!");
      Logger01.log("用户尝试登录,登录失败!");
   }
}
image.png