关于java的File类,看了这篇就够了

目录

File的本质

File对象的3种类型:

普通类型:

斜杠开头的类型:

盘符开头的类型:

getAbsoluteFile()与getCanonicalFile()

File类的核心:file.listFiles()方法

File的常用方法:

综合案例:


 

File的本质

对java来说,File表示的是文件的路径,路径指向的文件可能是存在的,也可以是不存在的。可以是相对路径,也可以是绝对路径。File的本质,我们可以看成是一串字符串。指向了一个文件。File类有一个FileSystem成员变量,在进行大部分操作时,他都会用fileSystem对象解释这个路径。

/* File类源码节选  */
public class File
    implements Serializable, Comparable<File>
{

    private static final FileSystem fs = DefaultFileSystem.getFileSystem();
    .....
}

fileSystem对象会怎样解释路径呢?主要分3种情况:

 

File对象的3种类型:

File主要有3种类型:在调用各种file方法前,fileSystem对象会对file保存的路径进行解释,这时候就会体现出区别。

普通类型:

"ok.txt"这个文件名,表示文件是在当前上下文路径的“ok.txt”,fileSystem会认为file指向的文件是处于当前上下文路径下的。因此对fileSystem来说,new File("ok.txt")就是指向 “上下文路径/ok.txt”的文件。

斜杠开头的类型:

“/ok.txt”表示在最外层根目录(我的是D盘)下的ok.txt。fileSystem会认为file指向的文件是处于跟目录下的。因此对fileSystem来说,new File("/ok.txt")就是指向 “C:/ok.txt”的文件,在解释真实位置时,不会给file路径加上上下文路径的全部,而只是加上上下文路径所在的盘符。

盘符开头的类型:

盘符开头的路径,是一个绝对路径,因此“D:/ok.txt”则是一个绝对路径,fileSystem会认为file就是绝对路径,在执行操作之前,不会再解释。他跟斜杠开头的区别是:斜杠开头会在解释时给file路径加上盘符,而盘符开头的类型则不会加。

ps: 如果想表示上下文路径本身,应该用new File(".")

/**
 * 3种不同类型的file对象在调用getAbsoluteFile()时的不同结果
 */
public class FileTest {
    public static void main(String[] args) {
        //第一种类型
        File type_1 = new File("ok.txt");
        System.out.println("type_1.getAbsoluteFile() = " + type_1.getAbsoluteFile());
        // D:\IdeaProjects\Blog\ok.txt   获得的是上下文路径+当前路径

        //第二种类型
        File type_2 = new File("/ok.txt");
        System.out.println("type_2.getAbsoluteFile() = " + type_2.getAbsoluteFile());
        //D:\ok.txt   盘符+当前路径

        //第三种类型
        File type_3 = new File("D:/ok.txt");
        System.out.println("type_3.getAbsoluteFile() = " + type_3.getAbsoluteFile());
        //D:\ok.txt   文件本身
    }
}

IDEA的当前上下文路径是工程文件夹,而找类则会在"工程文件夹/out/production/模块文件夹/"下开始找。

在window系统中,路径分隔符可以是“\\”或者"/",而在Linux中只能是"/",建议我们都用"/",可以通用。

 

getAbsoluteFile()与getCanonicalFile()

在介绍getAbsoluteFIle()和getCannonicalFile()之前,先说一个符号:".."

".."是指上级文件夹,new File("../123")表示跟当前上下文路径同级的“123”文件夹。

file.getAbsoluteFile()/file.getCanonicalFile()两个的效果差不多,但CannonicalFile的文件名会更规范

  1. getAbsoluteFile()只是把上下文所处的位置和相对路径强行插到一起,所以有可能会出现"D:\a\.\c.txt"或"D:\a\..\c.txt"这样的路径,
  2. getCanonicalFile()则是会处理"."和".."
  3. 两者都返回的file对象,只是外观上不同,不会改变fileSystem解释的结果,也就不会改变file路径所指向的最终文件。这是因为fileSystem解释路径时,会自动解释"."和".."符号。
public class AbsoluteTest {
    public static void main(String[] args) throws IOException {
        File file_1 = new File("./abc.txt");
        File file_2 = new File("../abc.txt");
        System.out.println("file_1.getAbsoluteFile() = " + file_1.getAbsoluteFile());
        System.out.println("file_2.getAbsoluteFile() = " + file_2.getAbsoluteFile());
        System.out.println("file_1.getCanonicalFile() = " + file_1.getCanonicalFile());
        System.out.println("file_2.getCanonicalFile() = " + file_2.getCanonicalFile());
    }
}

运行结果:
file_1.getAbsoluteFile() = D:\IdeaProjects\Blog\.\abc.txt
file_2.getAbsoluteFile() = D:\IdeaProjects\Blog\..\abc.txt
file_1.getCanonicalFile() = D:\IdeaProjects\Blog\abc.txt
file_2.getCanonicalFile() = D:\IdeaProjects\abc.txt

从上面代码可以看出,getCannonicalFile()会给出更加规范的文件名。

getCannonicalFile()解释".."的方法就是把路径往前推一格。

getAbsoluteFile()则是直接拼接。

 

File类的核心:file.listFiles()方法

file.listFiles()可以获取当前路径的所有子文件夹,以file[]的形式返回:

public class ListFileTest {
    public static void main(String[] args) {
        File currentFile = new File(".");  //定义当前上下文路径这个文件夹
        File[] files = currentFile.listFiles();
        for (File file : files) {
            System.out.println(file);  //遍历当前上下文路径的所有文件夹
        }
    }
}

运行结果:
.\.git
.\.idea
.\API_test
.\out

在以下情况下,listFiles()会返回null

       1、file所指向的文件不是文件夹

       2、file所指向的文件不存在

       3、JVM没有权限访问file所指向的文件

如果是文件夹但没有文件,则返回空数组。

他们都可以接受一个filter参数,来决定每个文件夹是存是留。

public class ListFileTest_2 {
    public static void main(String[] args) {
        File notExit = new File("notExit"); //定义不存在的文件夹
        File[] filesNotExit = notExit.listFiles();
        System.out.println("filesNotExit = " + filesNotExit);  //filesNotExit = null

        File empty = new File("empty");     //定义空的文件夹
        File[] filesInEmpty = empty.listFiles();
        System.out.println("filesInEmpty.length = " + filesInEmpty.length); //不为null,但filesInEmpty.length = 0

        File file = new File(".idea");
        File[] xmls = file.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                System.out.println("dir = " + dir);  //dir = .idea
                System.out.println("name = " + name);  //name = encodings.xml
                //过滤器自动帮我们把dir(文件夹)和文件名分开了
                return name.endsWith("xml");
            }
        });
        for (File xml : xmls) {
            System.out.println("xml = " + xml);
        }

        //xml = .idea\encodings.xml
        //xml = .idea\misc.xml
        //xml = .idea\modules.xml
        //xml = .idea\vcs.xml
        //xml = .idea\workspace.xml
    }
}

相对路径.listFile()得到的是相对路径的file列表,绝对路径.listFile()得到的是绝对路径的file列表。

如上所述,File在对文件执行操作的时候,会自动解释"."和".."符号,因此getAbsoluteFile()和getCanonicalFile()的区别,就是打印时候的区别。

public class AbsoluteTest {
    public static void main(String[] args) throws IOException {
        File file_1 = new File("./abc");
        File file_2 = new File("b/../abc");
        /*System.out.println("file_1.getAbsoluteFile() = " + file_1.getAbsoluteFile());
        System.out.println("file_2.getAbsoluteFile() = " + file_2.getAbsoluteFile());
        System.out.println("file_1.getCanonicalFile() = " + file_1.getCanonicalFile());
        System.out.println("file_2.getCanonicalFile() = " + file_2.getCanonicalFile());*/
        File file_1_AbsoluteFile = file_1.getAbsoluteFile();
        File file_2_AbsoluteFile = file_2.getAbsoluteFile();
        File file_1CanonicalFile = file_1.getCanonicalFile();
        File file_2CanonicalFile = file_2.getCanonicalFile();



        System.out.println("file_1CanonicalFile = " + file_1CanonicalFile);
        for (File file : file_1CanonicalFile.listFiles()) {
            System.out.println(file);
        }
        System.out.println("------------");
        System.out.println("file_2CanonicalFile = " + file_2CanonicalFile);
        for (File file : file_2CanonicalFile.listFiles()) {
            System.out.println(file);
        }
        System.out.println("------------");
        System.out.println("file_1_AbsoluteFile = " + file_1_AbsoluteFile);
        for (File file : file_1_AbsoluteFile.listFiles()) {
            System.out.println(file);
        }
        System.out.println("------------");
        System.out.println("file_2_AbsoluteFile = " + file_2_AbsoluteFile);
        for (File file : file_2_AbsoluteFile.listFiles()) {
            System.out.println(file);
        }
    }
}

运行结果:
file_1CanonicalFile = D:\IdeaProjects\Blog\abc
D:\IdeaProjects\Blog\abc\hello.txt
------------
file_2CanonicalFile = D:\IdeaProjects\Blog\abc
D:\IdeaProjects\Blog\abc\hello.txt
------------
file_1_AbsoluteFile = D:\IdeaProjects\Blog\.\abc
D:\IdeaProjects\Blog\.\abc\hello.txt
------------
file_2_AbsoluteFile = D:\IdeaProjects\Blog\b\..\abc
D:\IdeaProjects\Blog\b\..\abc\hello.txt

除了listFiles()方法,还有list()方法,返回的是String[],包含的信息比File[]少,视实际情况使用。

 

File的常用方法:

如文章开头所述,在执行如下大部分操作前,fileSystem对象都会根据路径解释路径,找到file所指向的文件,然后才执行下面的操作:

file.isDirectory()  文件是否为文件夹

file.isFile()   文件是否为文件

file.exists()   文件是否存在

file.createNewFile():跟formatter(),OutputStream()一样,如果作为参数的文件不存在,JVM都会帮你创建的,但是他不会帮你创建dir的!如果dir不存在,会直接报错!

f.getparent():  获得父母路径,

这个方法没有调用fileSystem来解释,只是简单地截取分隔符后面的字符串,因此若是new File("abc")生成的file调用这个方法,会获得null,先用getAbsolute()再用getParent()就OK!

file.mkDirs():可以把路径指向的文件当成dir创建,所以要小心hello.txt也被当成文件夹创建了。file.getParentFile().mkDirs()可以马上创建文件所需的dir(如果dir存在了则会不创建)

createNewFile()  和 mkDirs() 一样,如果文件存在,则返回false,成功则返回true

file.delete();   删除指定文件,如果文件是文件夹且里面有内容,则会返回false且不能删除

file.length() ;   获取文件的字节数,路径目标是文件夹,或路径目标文件不存在会返回0

file1.rename(file2) file1文件重命名为file2

file.getName(),返回最后一次被分隔符分割的文件名。

file.getPath()  返回当前路径,可能是相对路径,也可能是绝对路径,看File构造的时候传的参数是否盘符开头。

file.getAbsolutePath():  获取文件的绝对路径,如上文所述,他不会处理“."或者".."这个符号的。

file.getCanonicalPath(): 获取文件的规范路径,也就是处理了"."和".."之后的路径。

file.lastModified()  最后编辑时间,若文件真实存在则返回long,否则返回0。

file.isFile()    /   f.isDirectory()   判断是文件还是文件夹。

file.setReadable() / f.canRead();   顾名思义

file.setWritable() / f.canWrite();   顾名思义

File.createTempFile()  在临时文件目录生成一个空文件,这个目录跟系统有关。

 

综合案例:

最后通过一个综合案例练习我们学到的知识:只需要输入文件名和过滤逻辑,就能获得文件名下的所有符合要求的文件集合:

/**
 * 获得指定文件夹下所有的java文件(不考虑子文件夹的)并输出到控制台
 */
public class TestDemo {
    public static void main(String[] args) {
        Set<File> walk = walk("..",".*\\.java");
        for (File file : Objects.requireNonNull(walk)) {
            System.out.println(file);
        }
    }

    public static Set<File> walk(File file, Predicate<File> predicate) {
        if (!file.exists()) return null;        //如果路径指向的文件不存在则返回null
        HashSet<File> fileHashSet = new HashSet<>();
        if (file.isFile()) {
            if (predicate.test(file)) fileHashSet.add(file);
        } else {
            File[] files = file.listFiles(f -> f.isDirectory() || predicate.test(f));
            if(files == null) return fileHashSet;       //如果访问权限不够,也可能得到空文件数组
            for (File fileListed : Objects.requireNonNull(files)) {
                fileHashSet.addAll(Objects.requireNonNull(walk(fileListed, predicate)));
            }
        }
        return fileHashSet;
    }

    public static Set<File> walk(File file) {
        return walk(file, ".*");
    }

    public static Set<File> walk(File file, String pattern) {
        return walk(file, f -> Pattern.matches(pattern, f.getName()));
    }

    public static Set<File> walk(String pathName) {
        return walk(new File(pathName));
    }

    public static Set<File> walk(String pathName, String pattern) {
        return walk(new File(pathName), pattern);
    }
}

本章所有源码已经上传github:https://github.com/huheman/Blog

本人水平有限,如您发下有错漏请在评论不吝指教。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值