这篇文章主要想介绍的就是File类,这个类既可以表示文件(文本、图片和视频),也可以表示文件夹(文件路径),因此使用起来也是非常方便。
1.文件(文本、图片和视频)
2.文件夹(文件路径)
主要是想写一下它的常用方法吧,还有比如遍历文件夹、查看文件夹里面某种类型的文件等操作
1.构造方法
File(File parent,String child)
File(String pathname)
File(String parent,String child)
构建文件对象的方法很多,直接传入文件所在的路径就可以得到文件对象,但是要注意,传入的路径参数应该是String类型的,所以传入 "C:\a.txt"
是不对的,因为 \
是转义字符,要想表示这个字符,就必须使用 \\
这样,当然不用 \
这个斜杠也是可以的,将文件路径写成 C:/a.txt
也是可以的,这里就是使用的反斜杠 /
,因此这两种方式都可以表示文件路径,但是使用反斜杠 /
这种方式并不推荐,具体完整的描述在下面说吧。
2.创建和删除方法
文件的创建
boolean createNewFile()
文件夹的创建
boolean mkdir() 单层路径
boolean mkdirs() 多层路径
当使用上面的构造方法创建了对于文件或文件夹的对象之后,其实只是相当于对传入路径的文件或文件夹有了一个引用,而不代表它们一定存在,如果不存在的话就需要创建它们了,而创建它们则可以使用上面列出的几个方法,对于文件的创建就应该使用 createNewFile()
方法,而文件夹则应该使用 mkdir()
和 mkdirs()
了,关于文件夹创建的两个方法,区别主要就是在于要创建的文件夹是单层的还是多层的,单层就是使用 mkdir()
,双层那就是使用 mkdirs()
了。
删除方法都是一样的
boolean delete()
不过需要注意的是,删除文件夹的时候,它里面不能存在文件或者文件夹,也就是说在删除文件夹的时候,要首先删除掉它里面的文件和文件夹,当然如果它里面的文件夹同时也包含文件或文件夹的话,那就应该使用一个递归删除的方法,循环地去遍历,循环地删除。
3.判断方法
File类提供了一些常用的判断方法
boolean exists() 判断文件或者文件夹是否存在
boolean isAbsolute() 判断当前的路径是否是绝对路径
boolean isDirectory() 判断当前的文件是否是文件夹
boolean isFile() 判断当前的文件是否是文件
boolean isHidden() 判断当前的文件是否是隐藏文件
其实看到名字就大致可以知道这些方法的用途了,确实是见名知意。
exist()
是用来判断文件或者文件夹是否存在的,比如在读对文件进行读写操作之前,就需要先判断一下,这样也会比较严谨。
isAbsolute()
方法则是用来判断调用该方法的路径是否为绝对路径,绝对路径一般就是从盘符出发的路径名,而与其相对应的便是相对路径,相对路径则是指一个文件相对于另一个文件所在的路径。
isDirectory()
则是用来判断调用该方法的对象是否是一个目录(文件夹),它一般与isFile()
这个方法结合使用,因为一般不是文件,那就是文件夹了,遍历一个目录的时候就需要进行这两者的区分了。
isFile()
则是用来判断调用该方法的对象是否是一个文件,是文件便可以执行操作文件的方法,也是对于文件和文件夹的一个区分。
isHidden()
则是用来判断这个文件是否是一个隐藏文件,测试这个方法可以先在文件的属性页面将文件设置为隐藏的,然后再调用这个方法查看结果。
4.获取方法
常用的获取方法有如下一些
File getAbsoluteFile()
String getAbsolutePath()
String getName()
String getParent()
File getParentFile()
String getPath()
long lastModified()
long length()
上面这些方法很多都可以两两分成一组,因为很多都是一个返回字符串,一个返回对象
File getAbsoluteFile()
String getAbsolutePath()
这两个就是一个典型的例子,当我只是想输出一个文件或文件夹的绝对路径时,那我只需要调用getAbsolutePath()
方法就可以了,因为打印信息的时候只需要字符串就可以满足功能了,而如果我还想使用这个路径做其它的功能,那就应该使用getAbsoluteFile()
了,这次返回便是一个对象,使用这个对象是可以再创建其它新的对象的,就和File类的构造方法是一样的,就可以传入一个表示路径的字符串,当然也可以是一个表示路径的File对象了。
String getParent()
File getParentFile()
这两个方法和上面的有同样的区别,那就是一个返回字符串,而另一个则是返回的对象,其实它们都是返回的父目录,只是表示方式不一样罢了。
String getName()
String getPath()
这两个方法就不是像之前的那样的联系了,第一个方法getName()
是得到文件的名称,文件名以及后缀名,第二个方法getPath()
是得到文件的路径,至于是绝对路径还是相对路径,就要看当初构造这个对象时使用的什么,当时传入的参数是什么,现在这个方法返回的就会是什么。
long lastModified()
long length()
第一个方法lastModified()
返回的是这个文件最后修改的毫秒数,因为是毫秒数,那就和Date类的对象有点像了,表示的是距离某个时间点到现在的毫秒数,因此是可以用这个返回的值去构建一个Date对象的;第二个方法length()
是返回当前文件的大小,单位是字节,如果需要得到比如兆(M)这样更加通用的格式,是需要自己进行转换的。
5.修改方法
boolean renameTo(File dest)
这个方法就是用来修改文件名称的,不过需要注意的是里面的参数不是String类型的,而是一个File类型的,因此要先使用想要修改的文件名构造一个File对象,然后再用想要改变名称的文件对象调用这个方法。
6.几个应用的小例子
6.1 打印某个目录下指定类型的文件(包含子目录)
public static void main(String[] args) {
File file = new File("F:\\");
printJavaFile(file);
}
public static void printJavaFile(File file) {
if (file.isFile()) {
if (file.getName().endsWith(".pdf")
|| file.getName().endsWith(".pdf")) {
System.out.println(file.getPath());
}
} else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
printJavaFile(files[i]);
}
}
}
}
这个程序是打印出F盘符中所有pdf类型的文件,上面写的方法可以将文件目录传进去,其实方法中的文件类型也可以不用写死,比如pdf、java,也是可以设定一个String类型的参数进行传递的。
6.2 删除指定文件夹(包含文件和子文件夹)
public static void main(String[] args) {
File f = new File("D:\\360Downloads");
removeFile(f);
}
public static void removeFile(File file) {
if (file.isFile()) {
file.delete();
} else if (file.isDirectory()) {
File[] files = file.listFiles();
// 消除空指针异常
if (files != null) {
for (int i = 0; i < files.length; i++) {
File f = files[i];
removeFile(f);
}
}
file.delete();
}
}
删除文件,直接调用delete()
方法就好了,但是删除文件夹却需要多注意一点,如果文件夹里面还存在文件或子文件夹是删除不了的,因此如果想要删除文件夹就需要使用迭代方法了,是文件那就直接删除,但是如果是子文件夹,那就必须再去循环遍历这个子文件夹,里面是文件那就直接删除,如果还有子文件夹,那就再去遍历,当然当那个文件夹对象里面不存在东西的时候,也就可以调用delete()
方法了。
6.3 计算一个文件夹的大小
我们知道对于文件大小是有一个length()
方法的,返回的是这个文件的字节数,但是文件夹对象是没有这样的方法的,那最直接的方法就是把文件夹里面所有文件的大小加起来,那就是整个文件夹的大小了,所以这里我就先遍历一次文件夹,将文件夹里面的文件对象全部装到一个集合之中,然后再循环遍历这个集合,依次计算文件的大小,以此来计算文件夹的大小,这样计算就分为两步了,第一步是将文件装入集合当中,第二步就是计算集合中文件的大小,当然也可以直接在遍历集合的时候将文件的大小加起来,但感觉还是没有这样分为两步之后来的直观和好理解。
public static void main(String[] args) {
List<File> array = new ArrayList<File>();
File file = new File("D:\\Blog");
calFileSize(file, array);
long size = 0;
for (int i = 0; i < array.size(); i++) {
File f = array.get(i);
size += f.length();
}
System.out.println(size);
String big = MySizeTool.formatFileSize(size, true);
System.out.println(big);
}
public static void calFileSize(File file, List<File> array) {
if (file.isFile()) {
array.add(file);
} else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
File f = files[i];
calFileSize(f, array);
}
}
}
}
这里面最后得到所有文件的字节数之后,有一个将字节数转换单位的工具类,这里也直接放在下面了。
public class MySizeTool {
/**
* 通过字节数得到当前的格式化字符串数据
* @param size 字节数大小
* @param flag 是否保留2位小数. true表示保留,false表示不保留
* @return 格式化好的字符串数据,例如: 36MB 或者 36.30MB
*/
public static String formatFileSize(long size, boolean flag) {
// 定义需要返回的字符串
String result = null;
// 定义字符串
String grade = null;
// 定义整数部分和小数部分
long zhengShu = 0;
double xiaoShu = 0;
// 将size赋值
long mSize = size;
// 查看使用什么级别的数据
int count = -1;
while (mSize > 0) {
// 计算需要多少个1024
mSize /= 1024;
count++;
}
// 如果需要0-B 1-KB 2-MB 3-GB 4-TB 5-PB
switch (count) {
case 0:
result = size + "B";
break;
case 1:
zhengShu = size >> 10;
xiaoShu = 1.0 * size / 1024 - zhengShu;
grade = "KB";
break;
case 2:
zhengShu = size >> 20;
xiaoShu = 1.0 * size / 1024 / 1024 - zhengShu;
grade = "MB";
break;
case 3:
zhengShu = size >> 30;
xiaoShu = 1.0 * size / 1024 / 1024 / 1024 - zhengShu;
grade = "GB";
break;
case 4:
zhengShu = size >> 40;
xiaoShu = 1.0 * size / 1024 / 1024 / 1024 / 1024 - zhengShu;
grade = "TB";
break;
case 5:
zhengShu = size >> 50;
xiaoShu = 1.0 * size / 1024 / 1024 / 1024 / 1024 / 1024 - zhengShu;
grade = "PB";
break;
}
// 判断
if (count != 0) {
// 得到结果
result = calculate(flag, zhengShu, xiaoShu, grade);
}
// 返回数据
return result;
}
// 用于计算的操作
private static String calculate(boolean flag, long zhengShu,
double xiaoShu, String grade) {
String result;
String xs;
xs = xiaoShu + "";
// 去掉前面两个字符 0
// 是否可以保留数据
if (flag == true) {
if (xs.length() < 2) {
xs = ".00";
} else {
xs = xs.substring(1, 4);
}
result = zhengShu + xs + grade;
} else {
result = zhengShu + grade;
}
return result;
}
}
6.4 确定一个文件目录中文件类型以及各种类型文件的个数
解决这个问题主要是分两步,首先是要确定这个路径下有哪些类型的文件,当然主要是看文件的后缀名了,第二步再是去确定各个类型文件的数量,就是在遍历的过程中碰到某一种类型的文件,先将这种类型文件的数量取出来,然后在加1之后,再保存回去,这样就相当于增加了这一类型文件的数量。
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
public class Test3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入一个文件夹路径:");
String path = sc.nextLine();
File file = new File(path);
Map<String, Integer> map = new HashMap<String, Integer>();
getKey(file, map);
getNum(file, map);
Set<Entry<String, Integer>> entrys = map.entrySet();
for (Entry<String, Integer> entry : entrys) {
String key = entry.getKey();
int num = entry.getValue();
if (key == null) {
System.out.println("没有后缀名的文件有" + num + "个");
} else {
System.out.println(key + "类型的文件有" + num + "个");
}
}
}
public static void getKey(File file, Map<String, Integer> map) {
if (file.isFile()) {
if (!(file.getName().contains("."))) {
map.put(null, 0);
} else if (file.getName().contains(".")) {
String[] names = file.getName().split("\\.");
String key = names[names.length - 1];
map.put(key, 0);
}
} else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
File f = files[i];
if (f.isFile()) {
if (!(f.getName().contains("."))) {
map.put(null, 0);
} else if (f.getName().contains(".")) {
String[] names = f.getName().split("\\.");
String key = names[names.length - 1];
map.put(key, 0);
}
} else if (f.isDirectory()) {
getKey(f, map);
}
}
}
}
}
public static void getNum(File file, Map<String, Integer> map) {
if (file.isFile()) {
if (!(file.getName().contains("."))) {
int num = map.get(null);
map.put(null, num + 1);
} else if (file.getName().contains(".")) {
String[] names = file.getName().split("\\.");
String key = names[names.length - 1];
int num = map.get(key);
map.put(key, num + 1);
}
} else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
File f = files[i];
if (f.isFile()) {
if (!(f.getName().contains("."))) {
int num = map.get(null);
map.put(null, num + 1);
}
if (f.getName().contains(".")) {
String[] names = f.getName().split("\\.");
String key = names[names.length - 1];
int num = map.get(key);
map.put(key, num + 1);
}
} else if (f.isDirectory()) {
getNum(f, map);
}
}
}
}
}
}
7.文件分隔符
这里主要是想说一下文件分隔符,之前在构造函数中,说传入的字符串路径 C:\\a.txt
和 C:/a.txt
都是可以的,但是不推荐使用 C:/a.txt
,这是为什么呢?先说明一下反斜杠 /
,为什么它可以用作文件分隔符呢,是因为大部分Windows文件处理的函数调用都会将反斜杠 /
解释成文件分隔符,但是Windows系统函数的行为可能因为更新而发生变化,所以对于强调可移植性的程序来说,应该使用程序所运行平台的文件分隔符。
获取程序所运行平台的文件分隔符:
System.out.println(java.io.File.separator);
那就应该运行一下上面这条语句。没错会输出一个 \
,只不过 \
在Java中是转义字符,为了表示它,那就要使用 \\
了。
以上内容,我也是在《Java核心技术 卷II》中看到的,看来,读书还是可以得到很多细节的。
8.总结
看来提供的几个简简单单的方法,结合起来之后,就还可以写出蛮不错的程序,继续多敲多阅读吧!