您的位置:首页 > 编程语言 > Java开发

Java基础学习第二十一天——递归与字节流

2016-03-22 20:45 507 查看
文档版本开发工具测试平台工程名字日期作者备注
V1.02016.03.21lutianfeinone
V1.12016.05.17lutianfei修改与复习

递归

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

递归注意事项

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

次数不能太多,否则就内存溢出

构造方法不能递归使用

递归解决问题的思想

找到出口

找到规律

递归求阶乘案例







/* B:递归实现
*     a:做递归要写一个方法
*     b:出口条件
*     c:规律
*/
public class DiGuiDemo {
public static void main(String[] args) {
System.out.println("5的阶乘是:"+jieCheng(5));
}

/*
* 做递归要写一个方法:
*         返回值类型:int
*         参数列表:int n
* 出口条件:
*         if(n == 1) {return 1;}
* 规律:
*         if(n != 1) {return n*方法名(n-1);}
*/
public static int jieCheng(int n){
if(n==1){
return 1;
}else {
return n*jieCheng(n-1);
}
}
}


递归练习

兔子问题(斐波那契数列)

public class DiGuiDemo2 {
public static void main(String[] args) {
System.out.println(fib(20));
}

/*
* 方法: 返回值类型:int 参数列表:int n 出口条件: 第一个月是1,第二个月是1 规律: 从第三个月开始,每一个月是前两个月之和
*/
public static int fib(int n) {
if (n == 1 || n == 2) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
}


递归遍历目录下指定后缀名结尾的文件名称

/*
* 需求:请大家把E:\JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。
*
* 分析:
*         A:封装目录
*         B:获取该目录下所有的文件或者文件夹的File数组
*         C:遍历该File数组,得到每一个File对象
*         D:判断该File对象是否是文件夹
*             是:回到B
*             否:继续判断是否以.java结尾
*                 是:就输出该文件的绝对路径
*                 否:不搭理它
*/
public class FilePathDemo {
public static void main(String[] args) {
// 封装目录
File srcFolder = 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());
}
}
}
}
}


递归删除带内容的目录

/*
* 需求:递归删除带内容的目录
*
* 目录我已经给定:demo
*
* 分析:
*         A:封装目录
*         B:获取该目录下的所有文件或者文件夹的File数组
*         C:遍历该File数组,得到每一个File对象
*         D:判断该File对象是否是文件夹
*             是:回到B
*             否:就删除
*/
public class FileDeleteDemo {
public static void main(String[] args) {
// 封装目录
File srcFolder = 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());
}
}
}


IO流

IO流用来处理设备之间的数据传输

上传文件和下载文件

Java对数据的操作是通过
的方式

Java用于操作流的对象都在
IO包


IO流分类

按照数据流向

输入流 读入数据

输出流 写出数据

按照数据类型

字节流

字节输入流 读取数据 InputStream

字节输出流 写出数据 OutputStream

字符流

字符输入流 读取数据 Reader

字符输出流 写出数据 Writer

IO流常用基类

字节流
的抽象基类:

InputStream

OutputStream

字符流
的抽象基类:

Reader

Writer

注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。

如:InputStream的子类FileInputStream。

如:Reader的子类FileReader。

字节流写数据

FileOutputStream

FileOutputStream的构造方法

FileOutputStream(File file)

FileOutputStream(String name)

字节输出流操作步骤:

A:创建字节输出流对象

B:写数据

C:释放资源

为什么一定要close()呢?

A:让流对象变成垃圾,这样就可以被垃圾回收器回收了

B:通知系统去释放跟该文件相关的资源

public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = 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());
}
}


[b]字节流写数据的方式[/b]

public void write(int b):写一个字节

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

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

public class FileOutputStreamDemo2 {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
// OutputStream os = new FileOutputStream("fos2.txt"); // 多态
FileOutputStream fos = new FileOutputStream("fos2.txt");

// 调用write()方法
//fos.write(97); //97 -- 底层二进制数据 97对应的字符值 -- a
// fos.write(57);
// fos.write(55);

//public void write(byte[] b):写一个字节数组
byte[] bys={97,98,99,100,101};
fos.write(bys);

//public void write(byte[] b,int off,int len):写一个字节数组的一部分
fos.write(bys,1,3);

//释放资源
fos.close();
}
}


[b]字节流写数据常见问题[/b]

创建字节输出流到底做了哪些事情?

数据写成功后,为什么要close()?

如何实现数据的换行?

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

windows:
\r\n


linux:
\n


Mac:
\r


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

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

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

public class FileOutputStreamDemo3 {
public static void main(String[] args) throws IOException {
// 创建字节输出流对象
// FileOutputStream fos = new FileOutputStream("fos3.txt");
// 创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。
FileOutputStream fos = new FileOutputStream("fos3.txt", true);

// 写数据
for (int x = 0; x < 10; x++) {
fos.write(("hello" + x).getBytes());
fos.write("\r\n".getBytes());
}

// 释放资源
fos.close();
}
}


[b]字节流写数据加入异常处理[/b]

加入异常处理的IO流操作

public class FileOutputStreamDemo4 {
public static void main(String[] args) {

// 为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值
FileOutputStream fos = null;
try {
// fos = new FileOutputStream("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();
}
}
}
}
}


字节流读取数据

InputStream

FileInputStream

FileInputStream的构造方法

FileInputStream(File file)

FileInputStream(String name)

FileInputStream的成员方法

public int read()

public int read(byte[] b)

字节输入流操作步骤:

A:创建字节输入流对象

B:调用read()方法读取数据,并把数据显示在控制台

C:释放资源

/*
* 字节输入流操作步骤:
* A:创建字节输入流对象
* B:调用read()方法读取数据,并把数据显示在控制台
* C:释放资源
*
* 读取数据的方式:
* A:int read():一次读取一个字节
* B:int read(byte[] b):一次读取一个字节数组
*/
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
// FileInputStream(String name)
// FileInputStream fis = new FileInputStream("fis.txt");
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");

// // 调用read()方法读取数据,并把数据显示在控制台
// int by = fis.read();
// while (by != -1) {
// System.out.print((char) by);
// by = fis.read();
// }

// 最终版代码
int by = 0;
// 读取,赋值,判断
while ((by = fis.read()) != -1) {
System.out.print((char) by);
}

// 释放资源
fis.close();
}
}


[b]计算机如何识别中文[/b]

计算机是如何识别什么时候该把两个字节转换为一个中文呢?

在计算机中中文的存储分两个字节:

第一个字节肯定是负数。

第二个字节常见的是负数,可能有正数。但是没影响。

public class StringDemo {
public static void main(String[] args) {
// String s = "abcde";
// // [97, 98, 99, 100, 101]

String s = "我爱你中国";
// [-50, -46, -80, -82, -60, -29, -42, -48, -71, -6]

byte[] bys = s.getBytes();
System.out.println(Arrays.toString(bys));
}
}


字节流复制数据练习

把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中

/*
* 复制文本文件。
*
* 数据源:从哪里来
* a.txt -- 读取数据 -- FileInputStream
*
* 目的地:到哪里去
* b.txt -- 写数据 -- FileOutputStream
*
* java.io.FileNotFoundException: a.txt (系统找不到指定的文件。)
*
* 这一次复制中文没有出现任何问题,为什么呢?
* 上一次我们出现问题的原因在于我们每次获取到一个字节数据,就把该字节数据转换为了字符数据,然后输出到控制台。
* 而这一次呢?确实通过IO流读取数据,写到文本文件,读取一个字节,我就写入一个字节,没有做任何的转换。
* 它会自己做转换。
*/
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("a.txt");
// 封装目的地
FileOutputStream fos = new FileOutputStream("b.txt");

int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}

// 释放资源(先关谁都行)
fos.close();
fis.close();
}
}


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

/*
* 需求:把e:\\林青霞.jpg内容复制到当前项目目录下的mn.jpg中
*
* 数据源:
*         e:\\林青霞.jpg    --读取数据--FileInputStream
* 目的地:
*         mn.jpg--写出数据--FileOutputStream
*/
public class CopyImageDemo {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("e:\\林青霞.jpg");
// 封装目的地
FileOutputStream fos = new FileOutputStream("mn.jpg");

// 复制数据
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}

// 释放资源
fos.close();
fis.close();
}
}


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

/*
* 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中
*
* 数据源:
*         e:\\哥有老婆.mp4--读取数据--FileInputStream
* 目的地:
*         copy.mp4--写出数据--FileOutputStream
*/
public class CopyMp4Demo {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("e:\\哥有老婆.mp4");
// 封装目的地
FileOutputStream fos = new FileOutputStream("copy.mp4");

// 复制数据
int by = 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 {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("e:\\哥有老婆.mp4");
// 封装目的地
FileOutputStream fos = new FileOutputStream("copy.mp4");

// 复制数据
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}

// 释放资源
fos.close();
fis.close();
}
}


字节流读取数据两种方式图解比较

一次读取一个字节

一次读取一个字节数组

/*
* 一次读取一个字节数组:int read(byte[] b)
* 返回值其实是实际读取的字节个数。
*/
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
// 创建字节输入流对象
// FileInputStream fis = new FileInputStream("fis2.txt");
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");

// 最终版代码
// 数组的长度一般是1024或者1024的整数倍
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}

// 释放资源
fis.close();
}
}




字节缓冲流

通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非常好的。java开始在设计的时候,它也考虑到了这个问题,就专门提供了带缓冲区的字节类。这种类被称为:
缓冲区类(高效类)


写数据:BufferedOutputStream

读数据:BufferedInputStream

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

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

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

public class BufferedOutputStreamDemo {
public static void main(String[] args) throws IOException {
// BufferedOutputStream(OutputStream out)
// FileOutputStream fos = new FileOutputStream("bos.txt");
// BufferedOutputStream bos = new BufferedOutputStream(fos);
// 简单写法
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("bos.txt"));

// 写数据
bos.write("hello".getBytes());

// 释放资源
bos.close();
}
}


字节缓冲输入流

BufferedInputStream

/*
* 注意:虽然我们有两种方式可以读取,但是,请注意,这两种方式针对同一个对象在一个代码中只能使用一个。
*/
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException {
// BufferedInputStream(InputStream in)
BufferedInputStream bis = 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];
int len = 0;
while ((len = bis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}

// 释放资源
bis.close();
}
}


[b]字节缓冲流复制数据练习[/b]

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

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

四种方式比较复制效率

/*
* 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中
*
* 字节流四种方式复制文件:
* 基本字节流一次读写一个字节:    共耗时:117235毫秒
* 基本字节流一次读写一个字节数组: 共耗时:156毫秒
* 高效字节流一次读写一个字节: 共耗时:1141毫秒
* 高效字节流一次读写一个字节数组: 共耗时:47毫秒
*/

public class CopyMp4Demo {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
// method1("e:\\哥有老婆.mp4", "copy1.mp4");
// method2("e:\\哥有老婆.mp4", "copy2.mp4");
// method3("e:\\哥有老婆.mp4", "copy3.mp4");
method4("e:\\哥有老婆.mp4", "copy4.mp4");
long end = System.currentTimeMillis();
System.out.println("共耗时:" + (end - start) + "毫秒");
}

// 高效字节流一次读写一个字节数组:
public static void method4(String srcString, String destString)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
srcString));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destString));

byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}

bos.close();
bis.close();
}

// 高效字节流一次读写一个字节:
public static void method3(String srcString, String destString)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
srcString));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destString));

int by = 0;
while ((by = bis.read()) != -1) {
bos.write(by);

}

bos.close();
bis.close();
}

// 基本字节流一次读写一个字节数组
public static void method2(String srcString, String destString)
throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);

byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}

fos.close();
fis.close();
}

// 基本字节流一次读写一个字节
public static void method1(String srcString, String destString)
throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);

int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}

fos.close();
fis.close();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: