递归、字节流、文件复制_DAY20
1:递归(理解)
(1)方法定义中调用方法本身的现象。
(2)递归注意事项:
A:要有出口,否则就是死递归。
B:次数不能太多,否则内存溢出。
特殊事项:构造方法不能递归定义。
例子:cn.itcast.demo
package cn.itcast; /* * 递归算法: * 自己调用自己。 * 方法内定义:调用到什么程度,就不调用自己了。即递归出口。 */ public class Demo { public static void main(String[] args) { method(5); } public static void method(int flag){ System.out.println("我是一个递归方法调用前的代码"+flag); if(flag>0) { flag--; method(flag); System.out.println("我是一个递归方法调用后的代码"+flag); } else { System.out.println("递归出口出来了!"); return; } } }
(3)案例:(面试可能见到)
A:递归求1到10的和 例子:cn.itcast.Test
package cn.itcast; /* * 递归:将复杂问题分解,即复杂问题简单化。 * 使用递归求1-10的和。 * 10 + 1-9的和 * 9 + 1-8的和 * 8+ 1-7的和 * ... * 3+ 1-2和 * 2+ 1的和 * 1 返回1 */ public class Test { public static void main(String[] args) { System.out.println(getSum(3)); } //获取1到指定数字的和 public static int getSum(int number) { //递归出口:如果加到1了,则返回1。 if(number==1) { return 1; //如果不是1,就使用这个数,加上:1——比它小1的数的和。 }else { int nextNumber = number-1; return number + getSum(nextNumber); } } }
B:递归求阶乘 例子:cn.itcast.Test0
/** * 阶乘 * 10 * 9-1 * 9 * 8-1 * 8 * 7-1 * ... * 2 * 1 * 1 return 1; */ public class Factorial { public static void main(String[] args) { int max=4; int factorial=method(max); System.out.println(factorial); } public static int method(int max) { int fatorial=max; if(max==1){ return max; }else { fatorial=max*method(max-1); max--; } return fatorial; } }
C:递归求5的阶乘 例子:cn.itcast.Test2
package cn.itcast; /* * 递归:将复杂问题分解,即复杂问题简单化。 * 使用递归求5的阶乘。 */ public class Test2 { public static void main(String[] args) { System.out.println(getSum(5)); } //获取1到指定数字的积 public static int getSum(int number) { //递归出口:如果加到1了,则返回1。 if(number==1) { return 1; //如果不是1,就使用这个数,加上:1——比它小1的数的和。 }else { int nextNumber = number-1; return number * getSum(nextNumber); } } }
D:递归求兔子问题(斐波那契数列) cn.itcast.Test4; n.itcast.Test3
package cn.itcast; /* * 使用递归计算斐波那契数列 * 结果: 1 1 2 3 5 8 13 21 34... * number:1 2 3 4 5 * 计算到第几个数时,那个数是多少 */ public class Test3 { public static void main(String[] args) { System.out.println(method(7)); } //这个方法到底是干什么的?给我第几个数,我给你返回这一个数的值。!!!! public static int method(int number) { //number:第几个数 if(number == 1||number == 2) {//如果是前两个数,就返回1 return 1; } else { int before = number-1; //得到前一个数是第几个数 int beforeBefore = number-2; //得到前一个数的前一个数是第几个数 return method(before) + method(beforeBefore); //拿到前一个数的值,拿到前一个数的前一个数的值,相加,得到这个数。 } } }
package cn.itcast; /* * 一对兔子:每到第三个月,生一对兔子,之后每个月都生一对兔子。这一对小兔子,在第三个月时,生下一对兔子,之后每个月都生一对兔子。 * 注意: * 兔子,不生病,不死亡。 * 问某个月后,有多少对兔子? * 1 : 1 * A1 * 2 : 1 * A2 * 3 : 2 * A3 B1 * 4 : 3 * A3 C1 B2 * 5 : 5 * A3 D1 C2 B3 E1 * 6 : 8 * A3 F1 D2 C3 G1 B3 H1 E2 * 7 : 13 * A3 J1 F2 D3 K1 C3 L1 G2 B3 M1 H2 E3 N1 */ public class Test4 { public static void main(String[] args) { //使用斐波那契数列 } }
E:递归遍历目录(带内容的目录) cn.itcast.Test5
package cn.itcast; import java.io.File; /* * 递归输出指定目录下所有java文件的绝对路径 */ public class Test5 { public static void main(String[] args) { File file = new File("src"); method(file); } public static void method(File dir) { File[] listFiles = dir.listFiles(); for (File fileorDir : listFiles) { //如果是文件夹 if(fileorDir.isDirectory()) { System.out.println("dir:"+fileorDir.getName()); method(fileorDir); } else { //如果是文件 if(fileorDir.getName().endsWith(".java")) //判断文件名是否以.java结尾 System.out.println(fileorDir.getAbsolutePath()); } } } }
F:递归删除目录(带内容的目录) cn.itcast.Test6
package cn.itcast; import java.io.File; /* * 递归删除指定文件夹 */ public class Test6 { public static void main(String[] args) { File dir = new File("a"); method(dir); } public static void method(File dir) { //先删除内容 //返回该目录下所有的文件及文件夹对象 File[] listFiles = dir.listFiles(); for (File fileorDir : listFiles) { if(fileorDir.isDirectory()) { //删除这个文件夹 method(fileorDir); }else { //直接删除这个文件 System.out.println(fileorDir.getName()); fileorDir.delete(); } } //删除我自己 System.out.println(dir.getName()); dir.delete(); } }
2:IO(掌握)
(1)IO就是在不同设备间传递数据。
(2)IO流分类:
A:流向
输入流 读取数据
输出流 写出数据
B:数据类型
字节流
字节输入流 InputStream
文件字节输入流:FileInputStream 例子:cn.itcast3.demo2
package cn.itcast3; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Arrays; /* * 文件字节输入流:FileInputStream * 构造方法: * public FileInputStream(File file)throws FileNotFoundException。 * public FileInputStream(String name)throws FileNotFoundException。 * 主要方法: * public int read() throws IOException 一次读取一个字节 * public int read(byte[] b) throws IOException 一次读取一个字节数组 返回值为本次读到的字节个数 */ public class Demo2 { public static void main(String[] args) throws IOException { method2(); } public static void method() throws FileNotFoundException, IOException { //创建流对象 FileInputStream fis = new FileInputStream(new File("b.txt")); //读取输入 // int myByte = fis.read(); // System.out.println(myByte); // int myByte2 = fis.read(); // System.out.println(myByte2); // int myByte3 = fis.read(); // System.out.println(myByte3); // int myByte4 = fis.read(); // System.out.println(myByte4); // int myByte5 = fis.read(); // System.out.println(myByte5); int c; while((c=fis.read())!=-1) { System.out.println(c); } //关闭资源 fis.close(); } public static void method2() throws FileNotFoundException, IOException { //创建流对象 FileInputStream fis = new FileInputStream(new File("b.txt")); //b.txt内容: javav\r\n //读取输入 byte[] bytes = new byte[3]; // int len = fis.read(bytes); //{j,a,v} // System.out.println(len); // System.out.println(Arrays.toString(bytes)); // int len2 = fis.read(bytes); //{a,v,\r} // System.out.println(len2); // System.out.println(Arrays.toString(bytes)); // int len3 = fis.read(bytes); //{\n,v,\r} //v,\r重复读取了 // System.out.println(len3); // System.out.println(Arrays.toString(bytes)); int len; while((len=fis.read(bytes))!=-1) { // System.out.println(Arrays.toString(bytes)); System.out.println(new String(bytes, 0, len)); } //关闭资源 fis.close(); } }
字节输出流 OutputStream
文件字节输出流:FileOutputStream 例子:cn.itcast3.demo
package cn.itcast3; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; /* * 字节输出流:OutputStream * 00000000 00000000 00000000 0000 1111 15 * * 文件字节输出流:FileOutputStream * 构造方法: * public FileOutputStream(File file)throws FileNotFoundException 写出是覆盖操作,不是追加。 * public FileOutputStream(String name)throws FileNotFoundException 写出是覆盖操作,不是追加。 * public FileOutputStream(File file,boolean append)throws FileNotFoundException 布尔值为true,写出追加操作。 * public FileOutputStream(String name,boolean append)throws FileNotFoundException 布尔值为true,写出追加操作。 * 主要方法: * public void write(int b) throws IOException 写出一个字节 * public void write(byte[] b) throws IOException 写出一个字节数组 * * 注意: * 1:使用(File file)与(String name)参数的构造方法,写出是覆盖操作。 * 使用(File file,boolean append)与(String name,boolean append)参数的构造方法,写出是追加操作。 * 2:使用一次一个字节的方式,无法直接输出中文。可以使用一次一个字节数组的方式。 * 3:如果写出目标的这个文件不存在,则直接创建一个文件,再写出。 */ public class Demo { public static void main(String[] args) throws FileNotFoundException,IOException { method3(); } //一次输出一个字节。 public static void method() throws FileNotFoundException,IOException { //1创建流对象 FileOutputStream fos = null; try { File file = new File("b.txt"); fos = new FileOutputStream(file); //2写出内容 fos.write(-42); fos.write(-48); fos.write('9'); fos.write('7'); fos.write('中'); } catch (Exception e) { e.printStackTrace(); } finally { if(fos!=null) { //3关闭资源 fos.close(); } } } //一次输出一个字节数组。 public static void method2() throws FileNotFoundException,IOException { //1创建流对象 FileOutputStream fos = new FileOutputStream("b.txt"); //2准备写出的数据 // byte[] data = new byte[]{97,98,99,100}; //方式一 String sData = "java中国"; //方式二 byte[] data = sData.getBytes(); System.out.println(Arrays.toString(data)); //3写出内容 fos.write(data); //4关闭资源 fos.close(); } //一次输出一个字节数组。追加 public static void method3() throws FileNotFoundException,IOException { //1创建流对象 FileOutputStream fos = new FileOutputStream("b.txt",true); //2准备写出的数据 // byte[] data = new byte[]{97,98,99,100}; String sData = "java中国"; byte[] data = sData.getBytes(); System.out.println(Arrays.toString(data)); //3写出内容 fos.write(data); //4关闭资源 fos.close(); } }
例子:文件的复制 :cn.itcast3.demo3
package cn.itcast3; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /* * 文件复制: * 方式一:一次一个字节的复制。 * 方式二:一次一个字节数组的复制。 / */ public class Demo3 { public static void main(String[] args) throws IOException { method2(); } //一次一个字节: public static void method() throws FileNotFoundException, IOException { //创建流对象 FileInputStream fis = new FileInputStream("b.txt"); FileOutputStream fos = new FileOutputStream("b2.txt"); //读 int c; while((c=fis.read())!=-1) { //一次读一个字节 //写 fos.write(c); } //关闭流 fos.close(); fis.close(); } //一次一个字节数组: public static void method2() throws FileNotFoundException, IOException { //创建流对象 FileInputStream fis = new FileInputStream("b.txt"); FileOutputStream fos = new FileOutputStream("b2.txt"); //读 //定义字节数组用来接收读取到的字节们 byte[] bytes = new byte[4]; //定义变量,记录本次读取到的字节个数 int len; //循环读取文件内容 while((len = fis.read(bytes))!=-1) { //只要读到信息就进入循环体 //写 //一次写入长度为4的数组内容 fos.write(bytes,0,len); } //关闭流 fos.close(); fis.close(); } }
高效字节流:将原有IO流进行包装,使其效率更高。
高效字节输出流:BufferedOutputStream
高效字节输入流:BufferedInputStream
例子:cn.itcast3.demo4
package cn.itcast3; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /* * 高效字节流: * BufferedInputStream * BufferedOutputStream * * 构造方法:均要一个对应的流对象 * public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 * public BufferedInputStream(InputStream in)创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。创建一个内部缓冲区 * 数组并将其存储在 buf 中。 * */ public class Demo4 { public static void main(String[] args) throws IOException { long currentTimeMillis = System.currentTimeMillis(); //创建输入流对象 FileInputStream fis = new FileInputStream("b.txt"); BufferedInputStream bis = new BufferedInputStream(fis); //创建输出流对象 FileOutputStream fos = new FileOutputStream("b2.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); //读入 byte[] bytes = new byte[2]; int len; while((len=bis.read(bytes))!=-1) { //写出 bos.write(bytes, 0, len); bos.flush(); //刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中。 } //关闭流 bos.close(); bis.close(); long currentTimeMillis2 = System.currentTimeMillis(); System.out.println(currentTimeMillis2-currentTimeMillis); } }
字符流
字符输入流 Reader
字符输出流 Writer
注意:
A:四个顶层类都是抽象类。
B:一般每个体系的流都是以基类作为后缀名。
什么时候使用谁?
如果文件能够通过记事本打开并读懂,就用字符流。
其他的全部使用字节流。
3:字节流(掌握)
InputStream
|--FileInputStream
|--BufferedInputStream
OutputStream
|--FileOutputStream
|--BufferedOutputSteam
掌握:(4种方式)
是否使用数组
是否使用高效
把c:\\a.jpg复制到d:\\b.jpg中。
---------------------------------------
4、例子
(1):使用普通字节流完成文件复制
一次一个字节 188毫秒
一次一个字节数组 0毫秒
package cn; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * 文件复制: * (1)使用普通字节流,一次一个字节的复制。 * (2)使用普通字节流,一次复制一个字节数组。 */ public class Demo4 { public static void main(String[] args) throws IOException { long currentTimeMillis = System.currentTimeMillis(); //method(); //188毫秒 method2(); //1毫秒 long currentTimeMillis2 = System.currentTimeMillis(); System.out.println(currentTimeMillis2 - currentTimeMillis); } //(1)一次一个字节的复制。 public static void method() throws IOException { //创建流对象 FileInputStream fis = new FileInputStream("b.txt"); FileOutputStream fos = new FileOutputStream("b2.txt"); //读 int c; while ((c = fis.read()) != -1) { //写 fos.write(c); } //关闭流 fis.close(); fos.close(); } //(2)一次一个字节数组的复制。 public static void method2() throws IOException { //创建流对象 FileInputStream fis = new FileInputStream("b.txt"); FileOutputStream fos = new FileOutputStream("b2.txt"); //读 byte[] bytes = new byte[1024];//创建自己数组 int len;//保存每次读取的字节的长度 while ((len = fis.read(bytes)) != -1) { /* String s= new String(bytes,0,len); //写 fos.write(s.getBytes());*/ fos.write(bytes, 0, len); } //关闭流 fis.close(); fos.close(); } }
(2):使用高效字节流完成文件复制
一次一个字节 6毫秒
一次一个字节数组 0毫秒
package cn; import java.io.*; /** * (1)使用高效字节流,一次复制一个字节 * (2)使用高效字节流,一次复制一个字节数组 */ public class Demo5 { public static void main(String[] args) throws IOException { long currentTimeMillis = System.currentTimeMillis(); // method(); //6毫秒 method2(); //0毫秒 long currentTimeMillis2 = System.currentTimeMillis(); System.out.println(currentTimeMillis2 - currentTimeMillis); } //(1)使用普通字节流,一次复制一个字节数组 public static void method() throws IOException { //创建输入、输出流对象 FileInputStream fis = new FileInputStream("b.txt"); FileOutputStream fos = new FileOutputStream("b2.txt"); //创建高效输入、输出流对象 BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); //读 int c; while ((c = bis.read()) != -1) { //写 bos.write(c); } //关闭流 bos.close(); bis.close(); } //(2)使用高效字节流,一次复制一个字节数组 public static void method2() throws IOException { //创建输入、输出流对象 FileInputStream fis = new FileInputStream("b.txt"); FileOutputStream fos = new FileOutputStream("b2.txt"); //创建高效输入、输出流对象 BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); //读 int len; byte[] bytes = new byte[1024]; while ((len = bis.read(bytes)) != -1) { //写 bos.write(bytes, 0, len); bos.flush(); } //关闭流 bos.close(); bis.close(); } }
(3):比较四种方式的运算时间,并总结规律。