Java中IO流解析及代码实例详解

2022-07-22,,,,

目录
  • 1、io流
      • 什么是io流?
      • io流的分类?
      • 1、输入流(读文件):fileinputstream
      • 2、输出流(写文件):fileoutputstream

      1、io流

      1.流和流的分类

      什么是io流?

      i:input (输入)

      o: ouput(输出)

      io流的分类?

      有多种分类方式:

      • 一种方式是按照流的方向进行分类:

      以内存作为参照物

      往内存中去,叫做输入(input)。或者叫做读(read) .

      从内存中出来,叫做输出(output)。或者叫做写(write) .

      • 另一种方式是按照读取薮据方式不同进行分类:
        • 有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制。
        • 这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频……
        • 有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取

      总结:流的分类

      输入流、输出流、字节流、字符流

      java io流的四大家族

      java.io.inputstream 字节输入流
      java.io.outputstream 字节输出流
      java.io.reader 字符输入流
      java.io.writer 字符输出流

      注意:

      • 四个都是抽象类。
      • 所有流都是实现了java.io.closeable接口,都是可关闭的
        • 流是一个管道,是内存和硬盘之间的通道。用完后一定要关闭,不然会占用很多资源。
      • 所有的输出流都实现了java.io.flushable接口,都是可刷新的
        • 最终输出后,一定要记得调用flush()方法。目的是将管道中剩余未输出的数据强行输出完(清空管道)
        • 如果没有flash(),可能会导致丢失数据
      • 在java中只要”类名”以strean结尾的都是字节流。以"reader/writer"结尾的都是字符流

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

      文件专属:

      java . io.fileinputstream

      java.io.fileoutputstream

      java.io.filereader

      java.io.filewriter

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

      java . io . inputstreamreader

      java . io. outputstreamwriter

      缓冲流专属:

      java. io. bufferedreader

      java.io.bufferedwriter

      java.io. bufferedinputstream

      java . io.bufferedoutputstrean

      数据流专属:

      java . io . datainputstream

      java .io. dataoutputstrean

      标准输出流:

      java . io . printwriter

      java . io . printstream

      对象专属流:

      java.io.objectinputstream

      java.io.objectoutputstream

      一下子看到这么多流。不用怕,只需要掌握一组的使用方法就可以了,使用其他的都是一样,一通百通。

      下面以万能的字节流(fileinputstream、fileoutputstream)来举例说明。

      2.如何使用流

      1、输入流(读文件):fileinputstream

      方法一

      使用fileinputstream的read()

      步骤:

      1、 创建流对象

      ​ new fileinputstream(参数)

      ​ 参数可以是一个file类、string字符串表示的文件路径

      2、使用流的方法对文件进行读

      输入流调用read()方法,每次从流中读取一个数据字节。返回值是读到的字节的ascii值

      读取一个后,他会指向下一个字符,如果到达末尾。返回-1,可以用while()来实现。

      3、关闭流

      调用close()方法

      实例

      package com.io.stream;
      import java.io.fileinputstream;
      import java.io.filenotfoundexception;
      import java.io.ioexception;
      public class testfileinputstream {
          //定义一个流对象
          private static fileinputstream fis;
          public static void main(string[] args) {
              try {
                  //1、 创建流对象.参数可以是一个file类、string字符串表示的文件路径
                  fis = new fileinputstream("e:\\aaa.txt");//在e盘下有一个aaa.txt的文件夹,内容为(abcdefg)
                  //2、使用流的方法对文件进行读
                  while (true) {
                      int read = fis.read();//注意这里返回的是int类型,代表是字符的ascii值
                      if (read==-1) {//读到最后会返回-1,退出条件
                          break;
                      }
                      system.out.println(read);
                  }
              } catch (filenotfoundexception e) {//异常细粒化,不同异常可以选择不同的处理方式
                  e.printstacktrace();
              } catch (ioexception e) {
                  e.printstacktrace();
              } finally {
                  try {
                      //3、关闭流
                      fis.close();
                  } catch (ioexception e) {
                      e.printstacktrace();
                  }
              }
          }
      }
      

      /*输出
      97
      98
      99
      100
      101
      102
      103
      */

      int read()

      该方法因为每次都是只读取一个字节,这样内存和硬盘交互太频繁 ,开销大且效率不高。一般不使用,但是要了解,这是基础。

      方法二

      一般使用这种方法

      使用read(byte[] b)

      一次读取最多 b.length 个字节,减少内存和硬盘交互,提高执行效率

      该方法返回的是读到的字节的数量

      使用步骤:和前面只有第二步有些差别

      byte[] b= new byte[3];

      int readnum = fis.read(b);

      解析

      • 新建一个byte[]数组b,代表我们一次需要读多少个字符。读完这么多字符后,下次一读是从当前读到的位置开始,和上面一样
      • 将byte数组b传入read()方法中,返回一个我们byte数组的大小,此时readnum值为3

      那么我们读出来的数据在哪里呢。自然是存放在byte数组里。我们打印b数组看,发现b数组里存放的读到的ascii值

      细节:

      因为数组的长度是我们设定的。如果文件读到最后,不一定刚好符合我们设定的长度,最后一组的长度只有小于或等于数组的长度。如果小于它会返回剩余的字符的数量,读不到返回-1,我们可以利用这个作为循环退出的条件。

      另外一个,因为他的长度小于b数组,那么它的值也是无法填满b数组的,此时,它只更新b数组中前面的n个读到的值,b数组后面的是上一个读取时读取到的值。

      实例:

      仍然读取aaa.txt文件,内容为(abcdefg)

      import java.io.fileinputstream;
      import java.io.filenotfoundexception;
      import java.io.ioexception;
      import java.util.arrays;
      public class testfileinputstream2 {
          private static fileinputstream fis;
          public static void main(string[] args) {
              try {
                  fis = new fileinputstream("io流\\aaa.txt");
                  //准备一个byte数组
                  byte[] b= new byte[3];
                  int readnum = 0;
                  while (true) {
                      //先进行读操作。
                      readnum=fis.read(b);
                      //判断
                      if (readnum == -1) {
                          break;
                      }
                      //将字符数组转为string,后面两个参数为起始位置,和长度
                      string str = new string(b, 0, readnum);
                      system.out.println(str);
                  }
                  /*输出
      				abc
      				def
      				g
      			*/
              } catch (filenotfoundexception e) {
                  e.printstacktrace();
              } catch (ioexception e) {
                  e.printstacktrace();
              } finally {
                  try {
                      //关闭流
                      fis.close();
                  } catch (ioexception e) {
                      e.printstacktrace();
                  }
              }
          }
      }
      

      其他常用的方法

      int available()

      返回流中还有多少个字符没有读。(相当于获得文件读到的位置到末尾字符的个数,如果没开始读,返回文件中总字符的数量)

      使用这个可以对一些比较小的(字符长度)文件一次读完,如果不超过byte数组的范围的话

      public class testfileinputstream3 {
          public static void main(string[] args) throws ioexception {
              fileinputstream fis = new fileinputstream("io流\\aaa.txt");
              byte[] bytes = new byte[fis.available()];//创建一个和文件字符数量一样大的byte数组,文件不能太大。
              fis.read(bytes);
              system.out.println(new string(bytes));//b转为字符串,输出abcdefg
          }
      }
      

      skip(long n)

      顾名思义:从输入流中跳过并丢弃 n 个字节的数据。

      2、输出流(写文件):fileoutputstream

      和输入的流程差不多,过程也基本相同

      write(byte[] b)

      注意:

      • byte的范围是-128~127,超过会报错
      • 写完之后,一定要刷新
      • 如果当前路径下文件已存在,会将原文件清空,再写入(慎用)。
        • 如果它是一个目录,而不是一个常规文件,会报错。
        • 或者该文件不存在,但无法创建它,会报错。
      • 如果当前路径下文件不存在,会新建文件。
      package com.io.stream.output;
      import java.io.filenotfoundexception;
      import java.io.fileoutputstream;
      import java.io.ioexception;
      /**
       * @author cyh
       * @date 2021/8/7 17:21
       */
      public class test1 {
          private static fileoutputstream fos;
          public static void main(string[] args) {
              try {
                  //新建一个输出流,参数是输出的路径,最后的为文件名。
                  fos = new fileoutputstream("io流\\bbb.txt");
                  //新建一个byte数组,里面对应的是abcd的ascii值
                  byte[] bytes = {97, 98, 99, 100,101,127}; //注意byte的范围是-128~127
                  //输出流调用write方法写入byte数组,以文件形式保存到上面的路径
                  fos.write(bytes);
                  //写完之后,一定要刷新
                  fos.flush();
              } catch (ioexception e) {
                  e.printstacktrace();
              } finally {
                  try {
                      fos.close();
                  } catch (ioexception e) {
                      e.printstacktrace();
                  }
              }
          }
      }
      

      追加写文件

      想要追加写文件,则需要在新建流的的时候,加一个参数true。

      表示将字节写入文件末尾处,而不是写入文件开始处

      //新建一个输出流,参数是输出的路径,最后的为文件名。增加true表示开启追加写
      fos = new fileoutputstream("io流\\bbb.txt",true);
      

      注意:和上面一样,不一样的点只是追加写。

      write(byte[] b, int off, int len)

      将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流.

      意思就是,写入的内容为off~len。如果off是0,len是数组长度,那就全部写入;如果off是数组长度-1,len是数组长度,那就只写入了一个字符

      3.文件的拷贝

      • 使用fileinputstream+fileoutputstream即可完成文件的拷贝
      • 拷贝的过程应该是一边读、一边写
      • 使用上面的字节流拷贝文件的时候,文件类型随意,是万能的。什么文件都可以拷贝

      实例

      package com.io.stream.copy;
      import java.io.fileinputstream;
      import java.io.filenotfoundexception;
      import java.io.fileoutputstream;
      import java.io.ioexception;
      /**
       * @author cyh
       * @date 2021/8/7 17:53
       */
      public class testcopy {
          private static fileinputstream fis;
          private static fileoutputstream fos;
          public static void main(string[] args) {
              try {
                  //创建一个输入流
                  fis = new fileinputstream("d:\\edgedownload\\vscodeusersetup-x64-1.55.0.exe");
                  //创建一个输出流
                  fos = new fileoutputstream("c:\\users\\pc\\desktop\\copy\\b\\vscodeusersetup-x64-1.55.0.exe");
                  //核心,一边读、一边写
                  byte[] bytes = new byte[1024*1024];//1mb,一次最多拷贝1mb
                  int readnum=0;
                  while((readnum=fis.read(bytes))!=-1){
                      fos.write(bytes,0,readnum);//将bytes全部写入
                  }
                  //刷新
                  fos.flush();
              } catch (filenotfoundexception e) {
                  e.printstacktrace();
              } catch (ioexception e) {
                  e.printstacktrace();
              } finally {
                  //资源要分开释放,不然一个出错会导致另一个无法释放
                  try {
                      fis.close();
                  } catch (ioexception e) {
                      e.printstacktrace();
                  }
                  try {
                      fos.close();
                  } catch (ioexception e) {
                      e.printstacktrace();
                  }
              }
          }
      }
      

      总结

      本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注的更多内容!

      《Java中IO流解析及代码实例详解.doc》

      下载本文的Word格式文档,以方便收藏与打印。