一、概述
File 类在日常的开发中应当是不少见的,只要是涉及到文件读写的,往往都需要借助 File 类。本篇文章为笔者的读书笔记,将对 File 类的使用做一个简单的介绍,内容如下所示:
- File 是什么
- File 的构造方法
- File 的常用方法
- File 的简单例子
接下来我们就根据上面的列举出来的内容概要对 File 类进行较为详细的介绍。
二、什么是File
File 类是 java.io 包中唯一代表磁盘文件本身的对象。File 类定义了一些与平台无关的方法来操作文件来操作文件,可以通过调用 File 类的方法,实现创建、删除、重命名文件等操作。File 类的对象主要用来获取文件本身的一些信息,如文件所在的目录、文件的长度、文件的读写权限等。此外 File 类还有以下几点注意事项:
- File 对象除了能表示文件本身外,还能表示文件目录;
- File 对象并非就是文件本身,它实际上代表的是和实际文件的一种联系,是一个抽象的表现形式,这种联系通过虚拟机来维持;
- 从第二点可知,File 对象所指代的文件并不一定是真实存在的,它有可能为空。
在大致了解了 File 类的作用之后,接下来我们就从构造方法入手,来了解 File 类是如何使用的。
三、File 类的构造方法
File 类有以下 4 个构造方法,构造方法及其参数的含义如下表所示:
方法 | 说明 |
---|---|
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。 |
File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的 File实例。 |
File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的 File实例。 |
File(URI uri) | 通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。 |
接下来我们就通过几个例子来了解下它们各自的使用。
File(String pathname)
我们假定文件所在的位置为 C:\Users\Marck\Desktop\demo.jpg
。这是笔者电脑桌面上的一张图片,我们需要创建一个 File 实例来表示这张图片文件,代码如下所示:
public class FileDemo {
public static void main(String[] args) {
String path = "C:\\Users\\Marck\\Desktop\\demo.jpg";
// 构建File对象
File file = new File(path);
}
}
这里需要注意的是字符 '\'
需要使用转义字符 '\\'
来表示。
接着我们思考一个问题:上述的文件路径 C:\Users\Marck\Desktop\demo.jpg
是在 Windows 系统下的路径表示形式,但在其他操作系统上路径分隔符就未必是 '\'
了。那么是否有什么方法可以统一表示不同平台下的路径分隔符呢?
答案是采用符号 '/'
或者调用 File.separator
。上述图片的文件路径分隔符采用 '/'
来表示之后即为 C:/Users/Marck/Desktop/demo.jpg
,这种形式在任何平台下都是通用的;而调用 File.separator
的方式也可以达到同样的效果,上述路径在这种形式下表示为:
"C:" + File.separator + "Users" + File.separator + "Marck" + File.separator + "Desktop" + File.separator + "2.JPG";
它同样也可以达到跨平台通用的效果,但一般而言我们更愿意使用 '/'
的表示形式,因为调用 File.separator
的方式往往会比较麻烦。
File(String parent, String child)
依然以上面的图片文件路径 C:\Users\Marck\Desktop\demo.jpg
为例,将 C:\Users\Marck\Desktop
作为其父路径,代码如下所示:
public class FileDemo {
public static void main(String[] args) {
String parentPath = "C:/Users/Marck/Desktop";
File file = new File(parentPath, "demo.jpg");
}
}
通过该构造方法创建的 File 实例与第一种方法达到的效果是一致的。
File(File parent, String child)
这个构造方法其实和第二种构造方法的使用是非常相似的,只不过第一个参数 parent 的类型为 File,依旧以上面图片文件的路径为例创建该图片文件的 File 对象:
public class FileDemo {
public static void main(String[] args) {
File file = new File(new File("C:/Users/Marck/Desktop"), "demo.jpg");
}
}
通过该构造方法创建的 File 实例与第二种方法达到的效果是一致的。
File(URI uri)
这个构造方法应该是最不常使用的了,它需要借助统一资源标识符 URI 类来辅助构造 File 实例,代码如下所示:
public class FileDemo01 {
public static void main(String[] args) throws URISyntaxException {
URI uri = new URI("file:/C:/Users/Marck/Desktop/demo.jpg");
File file = new File("C:/Users/Marck/Desktop/demo.jpg");
}
}
由于 URI 的知识与本主题无关,所以这里只做简单介绍,上述代码创建出来的 File 实例与前面三种构造方法创建出来的实例效果是一致的。
四、File的常用方法
File 的方法非常的多,下面只列举出日常使用频率较高的几个方法,其它方法可以在 Java 官方文档中自行查看,常用方法如下表所示:
方法 | 说明 |
---|---|
getName() | 返回 File对象表示的文件或目录的名称。 |
getPath() | 返回 File对象的路径名字符串。 |
getAbsoultPath() | 返回 File对象的绝对路径名字符串。 |
getParent() | 返回 File对象的父路径名字符串,如果File对象没有父目录,则返回null。 |
exists() | 测试 File对象表示的文件或目录是否存在。 |
isFile() | 测试 File对象表示的文件是否为普通文件。 |
isDirectory() | 测试 File对象表示的文件是否为目录。 |
上表中的这些方法都比较简单,这里就不一一举例子了。唯一需要注意的是 getPath
方法,如果构建的 File 实例路径为相对路径,那么 getPath
返回的也是相对路径名,如果构建的 File 实例路径为绝对路径,那么 getPath
返回的就是绝对路径名,下列代码对其进行了验证:
public class FileDemo {
public static void main(String[] args) {
// 传入参数为相对路径
File file = new File("demo.jpg");
System.out.println(file.getPath());
// 传入参数为绝对路径
file = new File("C:/Users/Marck/Desktop/demp.jpg");
System.out.println(file.getPath());
}
}
输出结果如下:
demo.jpg
C:\Users\Marck\Desktop\demp.jpg
与上面我们所说的情况一致。接下来看到几个文件的列举方法,它们用于列举出目录中的文件:
方法 | 说明 |
---|---|
list() | 返回一个字符串数组,命名由 File对象表示的目录中的文件和目录。 |
list(FilenameFilter filter) | 返回一个字符串数组,命名由 File 对象表示的目录中满足指定过滤器的文件和目录。 |
listFiles() | 返回一个 File 数组,表示由 File对象表示的目录中的文件。 |
listFiles(FilenameFilter filter) | 返回一个 File 数组,命名由 File 对象表示的目录中满足指定过滤器的文件和目录。 |
listRoots() | File 类的静态方法,列出可用的文件系统根。 |
接下来通过几个例子来说明上述方法的使用。
list()
假设我们现在要列出桌面上的文件名,代码如下所示:
public class FileDemo {
public static void main(String[] args) {
File file = new File("C:/Users/Marck/Desktop");
String[] files = file.list();
for (String s : files){
System.out.println(s);
}
}
}
运行结果如下:
360安全浏览器.lnk
Atom.lnk
Charles.lnk
Cisco Packet Tracer.lnk
CodeBlocks.lnk
…
可以看到成功地打印出了当前目录下的所有文件和目录,如果 File 实例代表的是一个文件对象,list
方法会返回 null。
listFiles()
listFiles
方法和 list
方法是很相似的,只不过 list
返回的是文件名的字符串数组,而 listFiles
返回的则是 File 数组,代码如下所示:
public class FileDemo {
public static void main(String[] args) {
File file = new File("C:/Users/Marck/Desktop");
File[] files = file.listFiles();
for (File f : files){
System.out.println(f.getPath());
}
}
运行结果如下所示:
C:\Users\Marck\Desktop\360安全浏览器.lnk
C:\Users\Marck\Desktop\Atom.lnk
C:\Users\Marck\Desktop\Charles.lnk
C:\Users\Marck\Desktop\Cisco Packet Tracer.lnk
C:\Users\Marck\Desktop\CodeBlocks.lnk
…
如果 File 对象代表的是一个文件而不是一个目录的话,同样会返回 null。
listRoots()
listRoots
方法返回的是文件系统的根目录,需要注意的是它是 File 类的静态方法,返回的是 File 数组。代码如下所示:
public class FileDemo {
public static void main(String[] args) {
File[] files = File.listRoots();
for (File f : files){
System.out.println(f.getPath());
}
}
}
运行结果如下:
C:\
D:\
E:\
笔者使用的是 Windows 系统,所以返回的是系统中三个盘的盘符。而如果是在 Linux 系统下运行此段代码,运行结果如下所示:
/
这和我们的认知也是一致的。接下来我们来了解如何使用 File 来创建/删除文件/目录。
方法 | 说明 |
---|---|
mkdir() | 创建由此 File 对象命名的目录。如果 File 对象路径中包含不存在的目录,创建失败。 |
mkdirs() | 创建由此 File 对象命名的目录,包括任何必需但不存在的父目录。 |
createNewFile() | 当且仅当具有该名称的文件尚不存在时,创建一个由此 File 对象命名的新的空文件。 |
delete() | 删除此 File 对象表示的文件或目录。 |
接下来通过例子来介绍这些方法的使用。
mkdir & mkdirs
这两个方法都是用于创建文件目录的,唯一的区别是如果 File 对象路径中包含不存在的目录,mkdir
会创建失败,而 mkdirs
方法则会创建出所有不存在的目录。举一个例子:在 C:/Users/Marck /Desktop
这个路径下,我们要创建一个 Temp
目录,Temp
目录还要再创建一个 child
子目录,那么它可表示为:C:/Users/Marck/Desktop/Temp/child
。注意此时 Temp
目录和 child
目录均是不存在的。
我们试着用 mkdir
方法来创建 child
目录,代码如下所示:
public class FileDemo {
public static void main(String[] args) {
File file = new File("C:/Users/Marck/Desktop/Temp/child");
boolean flag = file.mkdir();
System.out.println(flag);
}
}
我们用一个 boolean
变量 flag
来接收 mkdir
方法的返回值,打印出结果值来判断是否创建成功,运行代码,输出结果如下:
false
表示创建 child
目录失败,其实原因也很简单,child
的父目录 Temp
是还未存在的,所以 mkdir
方法无法创建 child
目录。所以 mkdir
方法创建成功必须保证该目录下的父目录都是存在的,上述的情况适宜使用 mkdirs
方法,它的好处是只要该路径下的目录不存在那么就会创建出来,代码如下所示:
public class FileDemo {
public static void main(String[] args) {
File file = new File("C:/Users/Marck/Desktop/Temp/child");
boolean flag = file.mkdirs();
System.out.println(flag);
}
}
运行结果如下所示:
true
我们去往桌面上查看时,也可以发现确实创建了 Temp
目录和它的子目录 child
。除此之外我们还得意识到一点是无论是 mkdir
还是 mkdirs
,当子目录已经存在时,会直接返回 false
。例如上述 mkdirs
的示例代码再运行一次,就会发现打印出来的结果是 flase
了,因为此时 child
目录已经存在了。
createNewFile()
createNewFile
方法用于创建新文件(注意不是目录),例如我们要在桌面上创建一个 1.txt
的文本文件,代码如下所示:
public class FileDemo {
public static void main(String[] args) throws IOException {
File file = new File("C:/Users/Marck/Desktop/1.txt");
boolean flag = file.createNewFile();
System.out.println(flag);
}
}
运行代码,结果如下所示:
true
去往桌面上查看时我们也可以发现确实新建了一个空文本文件 1.txt
。需要注意的是 createNewFile
方法会抛出 IOException
异常,并且当所在路径的 1.txt
文件存在的时候,同样也会返回 false
,表示文件创建失败。
delete()
delete
方法从名字上也能知道是用于删除文件或目录的方法,它在文件存在时删除成功并返回 true
,否则的话就会返回 false
,例子如下所示:
public class FileDemo01 {
public static void main(String[] args){
File file = new File("C:/Users/Marck/Desktop/1.txt");
boolean flag = file.delete();
System.out.println(flag);
}
}
运行结果如下:
true
表示成功地删除了文件 1.txt
。如果我们再运行一次上面的代码,会发现返回的是 false
,因为 1.txt
文件此时已经不存在了。
五、File的简单例子
这里我们通过 2 个小例子展示 File 的简单使用。
1. 列举出当前目录的所有文件名
通过前面的示例我们知道 list/listFiles
方法只能列举出当前目录下的文件,如果想要列举出目录下的所有文件,例如子目录下的文件,就可以使用到递归的方式来完成,代码如下所示:
public class FileDemo {
public static void main(String[] args){
File file = new File("C:/Users/Marck/Desktop");
printFilename(file);
}
public static void printFilename(File file){
// 递归终止条件:file 为空或者不存在
if (file == null || !file.exists()){
return;
}
// 打印文件名
System.out.println(file.getName());
// 如果文件为目录,回调自身,继续打印
if (file.isDirectory()){
for (File f : file.listFiles()){
printFilename(f);
}
}
}
}
2. 计算文件的大小
这个问题我们需要借助 File 的 length()
方法,它用于计算出文件的大小,单位为字节(byte)。值得注意的是如果调用该方法的 File 对象代表的是一个目录,那么它的返回值就为 0。所以我们同样需要遍历该目录下的所有文件,统计出所有文件的大小相加返回,代码如下所示:
public class FileDemo {
public static int totalLength = 0;
public static void main(String[] args){
File file = new File("C:/Users/Marck/Desktop/简历管理");
countLength(file);
System.out.println(totalLength);
}
public static void countLength(File file){
if (file == null || !file.exists()){
return;
}
if (file.isFile()){
totalLength += file.length();
} else {
for (File f : file.listFiles()){
countLength(f);
}
}
}
}
这里采用了一个静态变量辅助进行计算,可以看到 countLength
的思路实际上和第一题的思路并无二致,而更好的方法则由各位具体去发现了。例如可以将递归改为循环的方式从而避免 StackOverflow 的情况发生。
希望这篇文章对您有所帮助~