20. 递归和IO流(字节流和高效字节流)

来源:互联网 发布:测量编程视频教学 编辑:程序博客网 时间:2024/06/16 02:32

1:递归(理解)

       (1)方法定义中调用方法本身的现象

              方法的嵌套调用,这不是递归。

 Math.max(Math.max(a,b),c);

 public void show(int n) {

               if(n <= 0) {

                      System.exit(0);

               }

               System.out.println(n);

               show(--n);

 }

       (2)递归的注意事项;

              A:要有出口,否则就是死递归

              B:次数不能过多,否则内存溢出

              C:构造方法不能递归使用

 需求:请用代码实现求5的阶乘。

  下面的知识要知道:

             5! = 1*2*3*4*5

             5! = 5*4!

  有几种方案实现呢?

             A:循环实现

             B:递归实现

                    a:做递归要写一个方法

                    b:出口条件

                    c:规律

public class DiGuiDemo {       publicstatic void main(String[] args) {              intjc = 1;              for(int x = 2; x <= 5; x++) {                     jc*= x;              }              System.out.println("5的阶乘是:" + jc);                           System.out.println("5的阶乘是:"+jieCheng(5));       }        /* 做递归要写一个方法:        *          返回值类型:int        *          参数列表:int n        * 出口条件:        *          if(n== 1) {return 1;}        * 规律:        *          if(n!= 1) {return n*方法名(n-1);}*/       publicstatic int jieCheng(int n){              if(n==1){                     return 1;              }else{                     return n*jieCheng(n-1);              }       }}

       (3)递归的案例:

              A:递归求阶乘

              B:兔子问题

 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?

 分析:我们要想办法找规律

                    兔子对数

 第一个月:1

 第二个月:  1

 第三个月:  2

 第四个月:  3    

 第五个月:  5

 第六个月:  8

 ...

 由此可见兔子对象的数据是:

             1,1,2,3,5,8...

 规则:

             A:从第三项开始,每一项是前两项之和

             B:而且说明前两项是已知的

 如何实现这个程序呢?

             A:数组实现

             B:变量的变化实现

             C:递归实现

 假如相邻的两个月的兔子对数是a,b

 第一个相邻的数据:a=1,b=1

 第二个相邻的数据:a=1,b=2

 第三个相邻的数据:a=2,b=3

 第四个相邻的数据:a=3,b=5

 看到了:下一次的a是以前的b,下一次是以前的a+b

public class DiGuiDemo2 {       publicstatic void main(String[] args) {              //定义一个数组              int[]arr = new int[20];              arr[0]= 1;              arr[1]= 1;              //arr[2] = arr[0] + arr[1];              //arr[3] = arr[1] + arr[2];              //...              for(int x = 2; x < arr.length; x++) {                     arr[x]= arr[x - 2] + arr[x - 1];              }              System.out.println(arr[19]);//6765              System.out.println("----------------");              inta = 1;              intb = 1;              for(int x = 0; x < 18; x++) {                     //临时变量存储上一次的a                     inttemp = a;                     a= b;                     b= temp + b;              }              System.out.println(b);              System.out.println("----------------");               System.out.println(fib(20));       }       /*        * 方法: 返回值类型:int 参数列表:int n 出口条件: 第一个月是1,第二个月是1 规律: 从第三个月开始,每一个月是前两个月之和        */       publicstatic int fib(int n) {              if(n == 1 || n == 2) {                     return 1;              }else {                     return fib(n - 1) + fib(n - 2);              }       }}

              C:递归输出指定目录下所有指定后缀名的文件绝对路径

 需求:请大家把E:\JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。

 分析:

          A:封装目录

          B:获取该目录下所有的文件或者文件夹的File数组

          C:遍历该File数组,得到每一个File对象

          D:判断该File对象是否是文件夹

                 是:回到B

                 否:继续判断是否以.java结尾

                        是:就输出该文件的绝对路径

                        否:不搭理它

public class FilePathDemo {   public static void main(String[] args) {          //封装目录          FilesrcFolder = new File("E:\\JavaSE");          //递归功能实现          getAllJavaFilePaths(srcFolder);   }   private static void getAllJavaFilePaths(File srcFolder) {          //获取该目录下所有的文件或者文件夹的File数组          File[]fileArray = srcFolder.listFiles();          //遍历该File数组,得到每一个File对象          for(File file : fileArray) {                 //判断该File对象是否是文件夹                 if(file.isDirectory()) {                        getAllJavaFilePaths(file);                 }else {                        //继续判断是否以.java结尾                        if(file.getName().endsWith(".java")) {                               //就输出该文件的绝对路径                               System.out.println(file.getAbsolutePath());                        }                 }          }   }}

              D:递归删除带内容的目录(小心使用)

目录我已经给定:demo

 分析:

             A:封装目录

             B:获取该目录下的所有文件或者文件夹的File数组

             C:遍历该File数组,得到每一个File对象

             D:判断该File对象是否是文件夹

                    是:回到B

                    否:就删除

public class FileDeleteDemo {       public static void main(String[] args) {              //封装目录              FilesrcFolder = new File("demo");              //递归实现              deleteFolder(srcFolder);       }       private static void deleteFolder(File srcFolder) {              //获取该目录下的所有文件或者文件夹的File数组              File[]fileArray = srcFolder.listFiles();              if(fileArray != null) {                     //遍历该File数组,得到每一个File对象                     for(File file : fileArray) {                            //判断该File对象是否是文件夹                            if(file.isDirectory()) {                                   deleteFolder(file);                            }else {                                   System.out.println(file.getName()+ "---" + file.delete());                            }                     }                     System.out.println(srcFolder.getName()+ "---" + srcFolder.delete());              }       }}

2:IO(掌握)

       (1)IO用于在设备间进行数据传输的操作 

       (2)分类:

              A:流向

                     输入流    读取数据

                     输出流    写出数据

              B:数据类型

字节流

                           字节输入流    读取数据       InputStream

                           字节输出流    写出数据       OutputStream

                    字符流

                           字符输入流    读取数据       Reader

                           字符输出流    写出数据       Writer           

注意:

              a:如果我们没有明确说明按照什么分,默认按照数据类型分。

              b:除非文件用windows自带的记事本打开我们能够读懂,才采用字符流,否则建议使用字节流。

      (3)FileOutputStream写出数据

构造方法:

            FileOutputStream(Filefile)

             FileOutputStream(Stringname)

              A:操作步骤

                     a:创建字节输出流对象

                     b:调用write()方法

                     c:释放资源

public void write(intb):                                   写一个字节

  public void write(byte[] b):                              写一个字节数组

  public void write(byte[] b,int off,int len):           写一个字节数组的一部分

public class FileOutputStreamDemo2{   publicstatic void main(String[] args) throws IOException {          //创建字节输出流对象          //OutputStream os = new FileOutputStream("fos2.txt"); // 多态          FileOutputStreamfos = new FileOutputStream("fos2.txt");          //调用write()方法          //fos.write(97);//97 -- 底层二进制数据      --通过记事本打开 -- 找97对应的字符值 -- a          //fos.write(57);          //fos.write(55);          //publicvoid write(byte[] b):写一个字节数组          byte[]bys={97,98,99,100,101};          fos.write(bys);          //publicvoid write(byte[] b,int off,int len):写一个字节数组的一部分          fos.write(bys,1,3);          //释放资源          fos.close();   }}

              B:代码体现:

public class FileOutputStreamDemo{       publicstatic void main(String[] args) throws IOException {              //创建字节输出流对象              //FileOutputStream(File file)              //File file = new File("fos.txt");              //FileOutputStream fos = new FileOutputStream(file);              //FileOutputStream(String name)              FileOutputStreamfos = new FileOutputStream("fos.txt");               //创建字节输出流对象了做了几件事情:               // A:调用系统功能去创建文件               // B:创建fos对象               // C:把fos对象指向这个文件              //写数据              fos.write("hello,IO".getBytes());              fos.write("java".getBytes());              //释放资源              //关闭此文件输出流并释放与此流有关的所有系统资源。              fos.close();               // 为什么一定要close()呢?               // A:让流对象变成垃圾,这样就可以被垃圾回收器回收了               // B:通知系统去释放跟该文件相关的资源              //java.io.IOException:Stream Closed              //fos.write("java".getBytes());       }}

              C:要注意的问题?

                     a:创建字节输出流对象做了几件事情?

                     b:为什么要close()?

                     c:如何实现数据的换行?

                     d:如何实现数据的追加写入?

  如何实现数据的换行?

             为什么现在没有换行呢?因为你值写了字节数据,并没有写入换行符号。

             如何实现呢?写入换行符号即可呗。

             刚才我们看到了有写文本文件打开是可以的,通过windows自带的那个不行,为什么呢?

             因为不同的系统针对不同的换行符号识别是不一样的?

             windows:\r\n

             linux:\n

             Mac:\r

             而一些常见的个高级记事本,是可以识别任意换行符号的。

  如何实现数据的追加写入?

             用构造方法带第二个参数是true的情况即可

public class FileOutputStreamDemo3{       public static void main(String[] args) throws IOException {              //创建字节输出流对象              // FileOutputStream fos = newFileOutputStream("fos3.txt");              //创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。              FileOutputStreamfos = new FileOutputStream("fos3.txt", true);              //写数据              for(int x = 0; x < 10; x++) {                     fos.write(("hello"+ x).getBytes());                     fos.write("\r\n".getBytes());              }              //释放资源              fos.close();       }}

e:加入异常处理的字节输出流操作

public classFileOutputStreamDemo4 {       public static void main(String[] args) {              // 分开做异常处理              // FileOutputStream fos = null;              // try {              // fos = new FileOutputStream("fos4.txt");              // } catch (FileNotFoundException e) {              // e.printStackTrace();              // }              // try {              // fos.write("java".getBytes());              // } catch (IOException e) {              // e.printStackTrace();              // }              // try {              // fos.close();              // } catch (IOException e) {              // e.printStackTrace();              // }              // 一起做异常处理              // try {              // FileOutputStream fos = newFileOutputStream("fos4.txt");              // fos.write("java".getBytes());              // fos.close();              // } catch (FileNotFoundException e) {              // e.printStackTrace();              // } catch (IOException e) {              // e.printStackTrace();              // }              // 改进版// 为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值              FileOutputStream fos = null;              try {                     // fos = newFileOutputStream("z:\\fos4.txt");                     fos = new FileOutputStream("fos4.txt");                     fos.write("java".getBytes());              } catch (FileNotFoundException e) {                     e.printStackTrace();              } catch (IOException e) {                     e.printStackTrace();              } finally {                     // 如果fos不是null,才需要close()                     if (fos != null) {                            // 为了保证close()一定会执行,就放到这里了                            try {                                   fos.close();                            } catch (IOException e) {                                   e.printStackTrace();                            }                     }              }       }}

      (4)FileInputStream读取数据

              A:操作步骤

                     a:创建字节输入流对象

                     b:调用read()方法

                     c:释放资源

读取数据的方式:

 A:int read():一次读取一个字节

 B:int read(byte[] b):一次读取一个字节数组

              B:代码体现:

public class FileInputStreamDemo {       publicstatic void main(String[] args) throws IOException {              //FileInputStream(String name)              //FileInputStream fis = new FileInputStream("fis.txt");              FileInputStreamfis = new FileInputStream("FileOutputStreamDemo.java");              //// 调用read()方法读取数据,并把数据显示在控制台              //// 第一次读取              //int by = fis.read();              //System.out.println(by);              //System.out.println((char) by);              //// 第二次读取              //by = fis.read();              //System.out.println(by);              //System.out.println((char) by);              //// 第三次读取              //by = fis.read();              //System.out.println(by);              //System.out.println((char) by);              //// 我们发现代码的重复度很高,所以我们要用循环改进              //// 而用循环,最麻烦的事情是如何控制循环判断条件呢?              //// 第四次读取              //by = fis.read();              //System.out.println(by);              //// 第五次读取              //by = fis.read();              //System.out.println(by);          ////通过测试,我们知道如果你读取的数据是-1,就说明已经读取到文件的末尾了              //用循环改进              //int by = fis.read();              //while (by != -1) {              //System.out.print((char) by);              //by = fis.read();              //}              //最终版代码              intby = 0;              //读取,赋值,判断              while((by = fis.read()) != -1) {                     System.out.print((char)by);              }              //释放资源              fis.close();       }}

 * 一次读取一个字节数组:int read(byte[] b)

 * 返回值其实是实际读取的字节个数。

public class FileInputStreamDemo2{       publicstatic void main(String[] args) throws IOException {              //创建字节输入流对象              //FileInputStream fis = new FileInputStream("fis2.txt");              FileInputStreamfis = new FileInputStream("FileOutputStreamDemo.java");              // 读取数据              //定义一个字节数组              //第一次读取              //byte[] bys = new byte[5];              //int len = fis.read(bys);              //// System.out.println(len);              //// System.out.println(new String(bys));              //// System.out.println(new String(bys, 0, len));              //System.out.print(new String(bys, 0, len));              //// 第二次读取              //len = fis.read(bys);              //// System.out.println(len);              //// System.out.println(new String(bys));              //// System.out.println(new String(bys, 0, len));              //System.out.print(new String(bys, 0, len));              //// 第三次读取              //len = fis.read(bys);              //// System.out.println(len);              //// System.out.println(new String(bys));              //// System.out.println(new String(bys, 0, len));              //System.out.print(new String(bys, 0, len));              //// 第四次读取              //len = fis.read(bys);              //// System.out.println(len);              //// System.out.println(new String(bys, 0, len));              //System.out.print(new String(bys, 0, len));              //// 代码重复了,用循环改进              //// 但是,我不知道结束条件              //// len = fis.read(bys);              //// System.out.println(len);              //// len = fis.read(bys);              //// System.out.println(len);              //// 如果读取到的实际长度是-1,就说明没有数据了              //byte[] bys = new byte[115]; // 0              //int len = 0;              //while ((len = fis.read(bys)) != -1) {              //System.out.print(new String(bys, 0, len));              //// System.out.print(new String(bys)); //千万要带上len的使用              //}              //最终版代码              //数组的长度一般是1024或者1024的整数倍              byte[]bys = new byte[1024];              intlen = 0;              while((len = fis.read(bys)) != -1) {                     System.out.print(newString(bys, 0, len));              }              //释放资源              fis.close();       }}

       (5)案例:2种实现

              A:复制文本文件

 * 复制文本文件。

 * 数据源:从哪里来

 * a.txt       --     读取数据       --     FileInputStream    

 * 目的地:到哪里去

 * b.txt      --     写数据           --     FileOutputStream

 * java.io.FileNotFoundException: a.txt (系统找不到指定的文件。)

 * 这一次复制中文没有出现任何问题,为什么呢?

 * 上一次我们出现问题的原因在于我们每次获取到一个字节数据,就把该字节数据转换为了字符数据,然后输出到控制台。

 * 而这一次呢?确实通过IO流读取数据,写到文本文件,你读取一个字节,我就写入一个字节,你没有做任何的转换。

 * 它会自己做转换。

public class CopyFileDemo {   publicstatic void main(String[] args) throws IOException {          //封装数据源          FileInputStreamfis = new FileInputStream("a.txt");          //封装目的地          FileOutputStreamfos = new FileOutputStream("b.txt");          intby = 0;          while((by = fis.read()) != -1) {                 fos.write(by);          }          //释放资源(先关谁都行)          fos.close();          fis.close();   }}


 * 需求:把c:\\a.txt内容复制到d:\\b.txt中

 * 数据源:

 *             c:\\a.txt   --     读取数据       --     FileInputStream

 * 目的地:

 *             d:\\b.txt   --     写出数据       --     FileOutputStream

public class CopyFileDemo {   publicstatic void main(String[] args) throws IOException {          //封装数据源          FileInputStreamfis = new FileInputStream("c:\\a.txt");          FileOutputStreamfos = new FileOutputStream("d:\\b.txt");          //复制数据          byte[]bys = new byte[1024];          intlen = 0;          while((len = fis.read(bys)) != -1) {                 fos.write(bys,0, len);          }          //释放资源          fos.close();          fis.close();   }}

              B:复制图片

 * 需求:把e:\\林青霞.jpg内容复制到当前项目目录下的mn.jpg中

 * 数据源:

 *             e:\\林青霞.jpg --读取数据--FileInputStream

 * 目的地:

 *             mn.jpg--写出数据--FileOutputStream

public class CopyImageDemo {   publicstatic void main(String[] args) throws IOException {          // 封装数据源          FileInputStreamfis = new FileInputStream("e:\\林青霞.jpg");          //封装目的地          FileOutputStreamfos = new FileOutputStream("mn.jpg");          //复制数据          intby = 0;          while((by = fis.read()) != -1) {                 fos.write(by);          }          //释放资源          fos.close();          fis.close();   }}

              C:复制视频

 * 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中

 * 数据源:

 *          e:\\哥有老婆.mp4--读取数据--FileInputStream

 * 目的地:

 *          copy.mp4--写出数据--FileOutputStream

public class CopyMp4Demo {       publicstatic void main(String[] args) throws IOException {              //封装数据源              FileInputStreamfis = new FileInputStream("e:\\哥有老婆.mp4");              //封装目的地              FileOutputStreamfos = new FileOutputStream("copy.mp4");              //复制数据              intby = 0;              while((by = fis.read()) != -1) {                     fos.write(by);              }              //释放资源              fos.close();              fis.close();       }}

 * 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中

 * 数据源:

 *          e:\\哥有老婆.mp4--读取数据--FileInputStream

 * 目的地:

 *          copy.mp4--写出数据--FileOutputStream

public class CopyMp4Demo {       publicstatic void main(String[] args) throws IOException {              //封装数据源              FileInputStreamfis = new FileInputStream("e:\\哥有老婆.mp4");              //封装目的地              FileOutputStreamfos = new FileOutputStream("copy.mp4");              //复制数据              byte[]bys = new byte[1024];              intlen = 0;              while((len = fis.read(bys)) != -1) {                     fos.write(bys,0, len);              }              //释放资源              fos.close();              fis.close();       }}

       (6)字节缓冲区流----缓冲区类(高效类)

 * 通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区                   还是非常好的。

 * 既然是这样的话,那么,java开始在设计的时候,它也考虑到了这个问题,就专门提供了带                    缓冲区的字节类。

           A:BufferedOutputStream

 * 构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就足够了。

 * 为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢?

 * 原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得                   靠基本的流对象实现。

public classBufferedOutputStreamDemo {   publicstatic void main(String[] args) throws IOException {          //BufferedOutputStream(OutputStream out)          //FileOutputStream fos = new FileOutputStream("bos.txt");          //BufferedOutputStream bos = new BufferedOutputStream(fos);          //简单写法          BufferedOutputStreambos = new BufferedOutputStream(                        newFileOutputStream("bos.txt"));          //写数据          bos.write("hello".getBytes());          //释放资源          bos.close();   }}


           B:BufferedInputStream

 * 注意:虽然我们有两种方式可以读取,但是,请注意,这两种方式针对同一个对象在一个代码中只能使用一个。

public class BufferedInputStreamDemo{       publicstatic void main(String[] args) throws IOException {              //BufferedInputStream(InputStream in)              BufferedInputStreambis = new BufferedInputStream(new FileInputStream(                            "bos.txt"));               //读取数据              //int by = 0;              //while ((by = bis.read()) != -1) {              //System.out.print((char) by);              //}              //System.out.println("---------");              byte[]bys = new byte[1024];              intlen = 0;              while((len = bis.read(bys)) != -1) {                     System.out.print(newString(bys, 0, len));              }              //释放资源              bis.close();       }}

      (7)案例:4种实现

              A:复制文本文件

              B:复制图片

              C:复制视频

 * 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中

 * 字节流四种方式复制文件:

 * 基本字节流一次读写一个字节:  共耗时:117235毫秒

 * 基本字节流一次读写一个字节数组:共耗时:156毫秒

 * 高效字节流一次读写一个字节:共耗时:1141毫秒

 * 高效字节流一次读写一个字节数组:共耗时:47毫秒

public class CopyMp4Demo {       publicstatic void main(String[] args) throws IOException {              longstart = System.currentTimeMillis();              //method1("e:\\哥有老婆.mp4","copy1.mp4");              //method2("e:\\哥有老婆.mp4","copy2.mp4");              //method3("e:\\哥有老婆.mp4","copy3.mp4");              method4("e:\\哥有老婆.mp4", "copy4.mp4");              longend = System.currentTimeMillis();              System.out.println("共耗时:" + (end - start) + "毫秒");       }       //高效字节流一次读写一个字节数组:       publicstatic void method4(String srcString, String destString)                     throwsIOException {              BufferedInputStreambis = new BufferedInputStream(new FileInputStream(                            srcString));              BufferedOutputStreambos = new BufferedOutputStream(                            newFileOutputStream(destString));               byte[]bys = new byte[1024];              intlen = 0;              while((len = bis.read(bys)) != -1) {                     bos.write(bys,0, len);              }              bos.close();              bis.close();       }       //高效字节流一次读写一个字节:       publicstatic void method3(String srcString, String destString)                     throwsIOException {              BufferedInputStreambis = new BufferedInputStream(new FileInputStream(                            srcString));              BufferedOutputStreambos = new BufferedOutputStream(                            newFileOutputStream(destString));              intby = 0;              while((by = bis.read()) != -1) {                     bos.write(by);              }              bos.close();              bis.close();       }       //基本字节流一次读写一个字节数组       publicstatic void method2(String srcString, String destString)                     throwsIOException {              FileInputStreamfis = new FileInputStream(srcString);              FileOutputStreamfos = new FileOutputStream(destString);              byte[]bys = new byte[1024];              intlen = 0;              while((len = fis.read(bys)) != -1) {                     fos.write(bys,0, len);              }              fos.close();              fis.close();       }       //基本字节流一次读写一个字节       publicstatic void method1(String srcString, String destString)                     throwsIOException {              FileInputStreamfis = new FileInputStream(srcString);              FileOutputStreamfos = new FileOutputStream(destString);              intby = 0;              while((by = fis.read()) != -1) {                     fos.write(by);              }              fos.close();              fis.close();       }}