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(); }}
- 20. 递归和IO流(字节流和高效字节流)
- 高效字节流bufferedinputstream和bufferedoutputstream
- IO流中字节流,高效字节流
- day-11-【IO【字节流、高效流】
- IO分两种流:字节流和字符流
- Java IO字符流和字节流
- io字节流和字符流
- Java-IO:字节流和字符流
- IO 字节流和字符流
- Java-IO-字节流和字符流
- java IO字符流和字节流
- Java IO 字节流 InputStream和OutputStream
- io流中的字节和字符
- IO字节流,OutputStream和InputStream
- io-字节和字符转换流
- Java--递归、字节流和集合综合
- 【字节流,高效流】
- 字节输入输出流:java.io.FileInputStream和java.io.FileOutputStream
- 工作日常整理大数据分区创建表实例
- IT行业的风投
- Android 获得设备状态信息、Mac地址、IP地址
- ANDROID HTML重定向之后返回原生view处理
- 使用gdal库拆分字符串
- 20. 递归和IO流(字节流和高效字节流)
- leetcode
- Java实现的软键盘并可以向Windows任意窗口发送中/英文信息
- 2017年浙江工业大学大学生程序设计迎新赛热身赛-E:递推(矩阵快速幂)
- 通过固定格式的DataFrame来创建VOC格式XML
- MS8413 光纤同轴解码 soundbar方案
- 最近了解到的知识点
- 搭建并配置splunk
- jquery 操作 checkbox 全选、反选、清除