递归
什么是递归?
递归是一种解决问题的有效方法,在递归过程中,函数将自身作为子例程调用。简单来说递归就是方法自己调用自己。和在方法内调用其他方法并没有太大区别,只是把其他方法换成了该方法本身。
注意:递归调用的细节:必须要求递归中有可以让函数调用的结束条件。否则函数一直调用,就会导致内存溢出。并且就算有结束条件,也有可能因为递归的太深,导致栈溢出。
递归例题:扫描某个文件下所有子文件夹及子子文件夹下的.java文件。
代码分析:
1.创建测试类Test;2.在Test类的main函数中创建一个File对象;3.调用递归扫描的函数scanFolders(parent);4.自定义函数scanFolders(),使用file对象调用listFiles()函数获得目录下所有的File数组files;5.循环遍历,获取每个file对象下子目录的对象file;6.使用file对象调用isDirectory()函数判断是否是文件夹;7.如果是文件夹,则递归调用scanFolders(file)函数;8.如果不是文件夹,肯定是文件,使用file对象调用getName()函数获得文件的全名,调用endsWith()函数判断后缀名是否是.jpg,如果是输出文件所属的文件名;(当遍历目录搜索指定文件时,当遍历到系统文件夹隐藏文件时,listFile()会返回null,则会报空指针异常,应进行判空操作)
代码实现:
public class Test {
static int count;
public static void main(String[] args) {
File file = new File("D:\\feisi");
scanFolders(file);
System.out.println("共有"+count+"个java文件");
}
private static void scanFolders(File file) {
File[] files = file.listFiles();
// 当遍历目录搜索指定文件时,当遍历到系统文件夹隐藏文件时,listFile()会返回null,则会报空指针异常,应进行判空操作
if (files != null) {
for (File file1 : files) {
if (file1.isFile() && file1.getName().endsWith(".java")) {
System.out.println(file1.getName());
count++;
} else {
scanFolders(file1);
}
}
}
}
}
IO流
什么是IO流?
io流其实简单来说就是input和output流,也就是输入输出流,java对数据的操作都是通过流来实现的,所以io流是java中非常重要的一部分。
按数据类型分:
IO流被分为字节流和字符流。
字节流:数据在持久设备上都是以二进制形式保存的。二进制就是字节数据。Java就给出了字节流可以直接操作字节数据。
字符流:读取字符数据。数据在设备上是以二进制形式表示,但是有些二进制合并在一起可以表示一些字符数据。
字节的输入输出流又被称为任意输入输出流,可以对任意类型的文件按照字节进行读和写的操作。字符输入输出流则只能对文本类型的文件进行操作。
FileInputStream和FileOutputStream文件的字节输入输出流。
FileInputStream常用方法:
read(byte[] b)作用:调用一次,读取多个字节数据,把读到的字节数据保存在传递的b字节数组中。
close():关闭流。
FileOutputStream常用方法:
write(byte[] b)作用:把这个b字节数组中的所有数据写到关联的设备中(设备包括文件、网络或者其他任何地方)。
close():关闭流。
案例:文件复制
代码分析:
1.定义一个整数变量len来记录当前给byte数组中读取的字节个数的;2.定义的字节数组b是用来存储从底层文件中读取到的多个字节数据;3.使用read(b)函数读取文件的时候需要传入一个数组参数b;4.每读取一次使用输出流对象调用write()函数向文件中写数据。
代码实现:
public class Test1 {
public static void main(String[] args) {
File file = new File("a.txt");
FileInputStream fis = null;
FileOutputStream fos = null;
int len = 0;
try {
//输入流对象
fis = new FileInputStream(file);
byte[] b = new byte[1024];
//输出流对象
fos = new FileOutputStream("C:\\Users\\hq\\Desktop\\" + file.getName());
//读取文件
while ((len = fis.read(b)) != -1) {
//输出文件
fos.write(b,0, len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fos != null) {
//关闭输出流
fos.close();
}
if (fis != null) {
//关闭输入流
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Filereader和FileWriter文件的字符输入输出流
这里两个类中的方法和它们对应的字节输入输出流的放方法有许多同名的方法,例如Filereader中的read(char[] cbuf)和字节的很想,作用也类似。虽然类似,但操作的对象却可能不同,字符输入输出流只能对文本文档操作,而字节输入输出流则还能对其它文件进行操作,例如:图片,视频等文件。
所以使用这两个类也可以实现文件的赋值,思路和方法和上述的字节型的基本一致,只需要将对象换成字符的输入输出和把字节数组改成字符数组。(和字节的不一样的就是需要在写完数据时使用flush()方法刷新一下缓冲区)
代码实现:
public class Test {
public static void main(String[] args) {
File file = new File("a.txt");
FileReader fr = null;
FileWriter fw = null;
int len = 0;
try {
//输入流对象
fr = new FileReader(file);
char[] b = new char[1024];
//输出流对象
fw = new FileWriter("C://Users//hq//Desktop//" + file.getName());
//读取文件
while ((len = fr.read(b)) != -1) {
//输出文件
fw.write(b,0, len);
fw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fw != null) {
//关闭输出流
fw.close();
}
if (fr != null) {
//关闭输入流
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}