JAVA中对于文件内容的操作使用IO流完成,但是对于文件属性和文件夹的相关操作则封装在了File对象中。File对象代表磁盘中实际存在的文件和目录。该类主要用于文件和目录的创建、文件的查找和文件的删除等。
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
File类当中有很多操作都可以搭配递归实现,效果更好,代码更简洁,逻辑更顺畅。这里我准备了四个案例:
需求一:
遍历一个文件夹当中的所有文件(包含子文件夹当中的文件内容)
逻辑分析:
1.获取一个文件夹当中所有文件的方法 listFiles
2.遍历获取到的文件数组,如果是文件,直接打印,如果是目录继续遍历.....
3.直到没有文件夹,所有文件都打印完为止。
代码如下:
public class FileTest {
static int fileCount=0,folderCount = 0;
public static void main(String[] args) {
File file = new File("E:\\answer");
showFileInfo(file);
System.out.println("当前目录下文件"+fileCount+"个,文件夹"+folderCount+"个");
}
public static void showFileInfo(File file){
if (!file.exists()||file.isFile()) { //如果文件不存在或不是文件夹对象则不遍历
return;
}
// 获取文件夹当中所有的文件,存放中数组中
File[] listFiles = file.listFiles();
// 遍历文件对象数组
for (File childFile : listFiles) {
if (childFile.isFile()) {
fileCount++; //文件数量自增
System.out.println("文件:"+childFile.getAbsolutePath());
}else{
folderCount++; //文件夹数量自增
System.out.println("文件夹:"+childFile.getAbsolutePath());
showFileInfo(childFile);
}
}
}
}
需求二:
编写代码,删除一个有多个层级内容的文件夹(即非空文件夹)。
逻辑分析:
1.file对象的delete方法可以删除文件和空文件夹对象,但是不能删除有内容的文件夹对象。
2.可以遍历文件夹目录,先删除其中的文件对象,然后在进入其子文件夹,删除其内部可删除内容,一层一层递进,删除完其中内容即可删除此文件夹。
3.因为反复执行,遍历文件夹和删除其中内容的工作,使用递归即可。
public class FileTest02 {
static int fileCount=0,folderCount = 0;
public static void main(String[] args) {
File file = new File("E:\\answer");
deleteFile(file);
}
public static void deleteFile(File file){
if (!file.exists()) { //判断是否存在
return;
}
if (file.isFile()) { //如果传入文件对象直接删除
file.delete();
return;
}
// 获取文件夹当中所有的文件,存放中数组中
File[] listFiles = file.listFiles();
// 遍历数组
for (File childFile : listFiles) {
if (childFile.isFile()) {
childFile.delete();
}else{
deleteFile(childFile); //调用当前的方法
// 删除文件夹空目录
childFile.delete();
}
}
file.delete();
}
}
接下来,准备加大难度了,准备好了么?我们依然针对删除操作。
需求三:
指定一个路径,删除其下面(含子文件夹中)的同名,同大小,同修改时间的重复文件,只保留一个
此题的含义在于,虽然windows不允许在一个文件夹出现同名文件,但可以在一个文件夹有多个文件和子文件夹,子文件夹当中出现于父目录相同的文件,而在规定的父目录中,我们只能保留一个,那应该如何解决呢?
逻辑分析:
1.File对象不仅包括名称,长度和修改时间等属性,还有其他的,故不能直接使用其对象判断,要创建一个只包含这三个属性的类。 方便判断是否已经存在。
2.需要将已经存在的对象信息存放到一个容器当中,可使用集合,List或者Set均可。
3.再次涉及文件夹多个层次的遍历,依然使用递归。
代码如下:
public class Test02 {
// 存储不相同的文件的容器
static List<MyFile>fileList = new ArrayList<MyFile>();
public static void main(String[] args) {
File file = new File("E:\\abc"); //可更改符合你要求的路径
deleteSameFile(file);
}
public static void deleteSameFile(File dirFile){
if (!dirFile.exists()||dirFile.isFile()) {
return;
}
// 获取文件夹当中的所有文件
File[] listFiles = dirFile.listFiles();
// 遍历数组,获取每一个
for (File childfile : listFiles) {
if (childfile.isFile()) {
MyFile myFile = new MyFile(childfile.getName(),
childfile.length(), childfile.lastModified());
if (fileList.contains(myFile)) {
childfile.delete();
}else{
fileList.add(myFile);
}
}else { //如果是文件夹
deleteSameFile(childfile);
}
}
}
}
class MyFile{
private String name; //文件名称
private long length; //文件字节大小
private long modifiedTime; //修改时间
public MyFile() {}
public MyFile(String name, long length, long modifiedTime) {
super();
this.name = name;
this.length = length;
this.modifiedTime = modifiedTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
public long getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(long modifiedTime) {
this.modifiedTime = modifiedTime;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (length ^ (length >>> 32));
result = prime * result + (int) (modifiedTime ^ (modifiedTime >>> 32));
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyFile other = (MyFile) obj;
if (length != other.length)
return false;
if (modifiedTime != other.modifiedTime)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "MyFile [name=" + name + ", length=" + length
+ ", modifiedTime=" + modifiedTime + "]";
}
}
通过以上三个案例,是不是感觉File类与递归搭配使用已经完全理解了呢?别着急,我们测试一下!
需求四:
指定一个路径,将其下面(含子文件夹中)的以".txt"结尾的文件移动到指定的另一个路径下
逻辑分析:
1.看到路径以及其子文件夹,相信做完了前面3道题的同学们,立即想到了递归操作,Bingo!完全正确。
2.文件移动到另一个路径下,这是剪切的操作呀,File对象中表达剪切的方法为renameTo(File destFile),参数可传入目标路径。
3.只需要.txt文件?可以使用文件过滤器,对于获取的文件数组进行过滤选择,把txt文件放出来,当然为了递归子文件夹,过滤时也要放出文件夹对象。
代码如下:
public class Test03 {
public static void main(String[] args) {
File srcFile = new File("E:\\det");
File destFile = new File("E:\\new");
renameFile(srcFile, destFile);
}
public static void renameFile(File dirFile,File destFile) {
if (!dirFile.exists()||dirFile.isFile()) {
return;
}
// 过滤获取txt文件和文件夹
File[] listFiles = dirFile.listFiles(new MyFileNameFilter());
for (File childfile : listFiles) {
if (childfile.isFile()) {
// 获取移动目标文件
File deFile = new File(destFile, childfile.getName());
childfile.renameTo(deFile); //移动文件
}else{
renameFile(childfile, destFile); //递归调用
}
}
}
}
//创建文件过滤器
class MyFileNameFilter implements FilenameFilter{
@Override
public boolean accept(File dir, String name) {
File file = new File(dir,name);
if (name.endsWith(".txt")||file.isDirectory()) {
return true;
}
return false;
}
}
ok!大家运行以上四个程序,就能够得到对应的效果了!不信你试试~~
感谢您的阅读~