学习阿里云大学零基础学Java系列 Java高级编程
1. File类说明
在Java语言里面提供有对于文件操作系统操作的支持,而这个支持就在java.io.File类中进行了定义,也就是说在整个java.io包里面,File类是唯一一个与文件本身操作(创建、删除、重命名等)有关的类,而如果想进行File类的操作,必须要提供有完整的路径,而后才可以调用相应的方法进行处理
2. File类的基本使用
打开jdk文档可以发现,File类是Comparable接口的子类,所以File类的对象是可以进行排序处理的。而在进行File类处理的时候需要为其设置访问路径,那么对于路径的配置主要通过File类的构造方法处理。
- 构造方法 File(String pathname) 设置要操作的完整路径
- 构造方法操作 File(String parent,String child) 设置父路径与子目录
如果想要进行文件的基本操作,可以使用如下的方法:
- 创建新的文件
public boolean createNewFile() throws IOException
- 判断文件是否存在
public boolean exists()
- 删除文件
public boolean delete()
范例:使用File类创建一个文件(d:\mldn.txt)
package IOKnowledge;
import java.io.File;
public class IOTest {
public static void main(String[] args) throws Exception{
File file = new File("d:\\mldn.txt");
if (file.exists()) {
file.delete();// 删除文件
} else {
System.out.println(file.createNewFile()); // 创建新的文件
}
}
}
通过代码可以发现,File类实现的就是文件本身的处理
3. File类深入操作
现在已经实现了文件的基础操作,但是对于这个操作里面也是存在有一些问题的,下面针对之前的代码进行优化处理
在实际的软件项目开发和运行的过程中,往往都会在window中进行项目的开发,而在项目部署的时候基于Linux或Unix来进行项目的发布以保证生产环境的安全性;
在不同的操作系统之中会存在不同的路径分隔符:window分隔符“\”、LInux分隔符“/”,所以在最初进行开发的时候必须考虑不同系统环境下的分隔符的区别,所以为了解决此问题,File类提供有一个常量:
public static final String separator
(常量命名没有大写,历史遗留问题)File file = new File("d:" + File.separator + "mldn.txt");
但是随着系统的适应性的不断加强,对于当前的路径操作,也可以随意使用了
File file = new File("d:/mldn.txt");// window系统下也支持此类书写,但是推荐使用File提供的分隔符常量
在使用File类进行文件处理时需要注意的是:程序->JVM->操作系统函数->文件处理(程序通过jvm,然后调用操作系统函数,再在磁盘上实现文件处理),所以在进行同一文件反复删除和创建的时候有可能会出现有延迟的问题,所以这个时候最好的方案是别重名(例如使用UUID);
在进行文件创建的时候有一个重要的前提:文件的父路径必须首先存在
File file = new File("d:" + File.separator + "hello" + File.separator + "demo" + File.separator + "message" + File.separator + "mldn.txt"); Exception in thread "main" java.io.IOException: 系统找不到指定的路径。 at java.io.WinNTFileSystem.createFileExclusively(Native Method) at java.io.File.createNewFile(Unknown Source) at IOKnowledge.IOTest.main(IOTest.java:23)
- 如何获取父路径
public File getParentFile()
- 父路径不存在则创建目录
public boolean mkdir()
创建单级路径public boolean mkdirs()
创建多级路径
package IOKnowledge; import java.io.File; public class IOTest { public static void main(String[] args) throws Exception{ File file = new File("d:" + File.separator + "hello" + File.separator + "demo" + File.separator + "message" + File.separator + "mldn.txt"); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs();// 创建父路径 } if (file.exists()) { file.delete();// 删除文件 } else { System.out.println(file.createNewFile()); // 创建新的文件 } } }
创建文件的标准形式
这种判断并且建立父目录的操作在很多的情况下可能只需要一次,但是如果将这个判断一直都停留在代码里面,那么就会造成时间复杂度的提升,所以这个时候如果要想提升性能,请先保证父目录已经创建,然后删除掉父目录是否存在的验证- 如何获取父路径
4. 获取文件信息
除了可以进行文件的操作之外也可以通过File类来获取一些文件本身提供的信息,可以获取如下内容:
- 文件是否可读
public boolean canRead()
- 文件是否可写
public boolean canWrite()
- 获取文件长度
public long length()
该方法返回的是long数据类型,字节长度 - 最后一次修改日期时间
public long lastModified()
- 判断是否是目录
public boolean isDirectory()
- 判断是否是文件
public boolean isFile()
// 获取文件信息
public static void main(String[] args) throws Exception{
File file = new File("d:" + File.separator + "hello" + File.separator + "demo" + File.separator + "message" + File.separator + "mldn.jpg");
System.out.println("文件是否可读:" + file.canRead());// 是否可读
System.out.println("文件是否可写:" + file.canWrite());// 是否可写
System.out.println("文件大小:" + file.length() + "字节");// 文件大小
System.out.println("文件大小:" + MathUtil.round(file.length() / (double)1024 / 1024, 2) + "MB");
System.out.println("最后的修改时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified())));
System.out.println("是否是目录:" + file.isDirectory());
System.out.println("是否是文件:" + file.isFile());
}
//数字工具类
class MathUtil {
private MathUtil() {};
public static double round(double num, int scale) {
return Math.round(Math.pow(10, scale) * num) / Math.pow(10, scale);
}
}
既然可以判断给定的路径是文件还是目录,那么就可以进一步的判断,如果发现是目录,则应该列出目录中的全部内容:
- 列出目录内容:
public File[] listFiles()
public static void main(String[] args) {
File file = new File("d:" + File.separator);
if (file.isDirectory()) {// 当前是一个目录
File [] result = file.listFiles();
for (int i = 0; i < result.length; i++) {
System.out.println(result[i]);
}
}
}
这些信息的获得都是文件或目录本身的操作,都是不涉及到我呢见内容处理的
5. File操作案例:列出指定目录中的全部文件
现在可以由开发者任意设置一个目录的路径,而后将这个目录中所有的文件的信息全部列出,包括子目录的所有文件,在这样的处理情况下最好的做法就是利用递归的形式来完成。
范例:程序实现
public static void main(String[] args) {
File file = new File("D:" + File.separator);// 是一个目录
listDir(file);
}
public static void listDir(File file) {
if (file.isDirectory()) {// 是一个目录
File [] result = file.listFiles();// 列出目录中的全部内容
if (result != null) {
for (int i = 0; i < result.length; i++) {
listDir(result[i]);// 依次判断执行
}
}
}
System.out.println(file);// 获得完整路径
}
如果现在将路径输出变为删除操作,那么就彻底删除路径了
6. File操作案例:批量修改文件名称
编写程序,程序运行时输入目录名称,并把该目录下的所有文件名后缀修改为.txt,对于这类的操作必须设置一些假设的约定,能够重命名的文件都是有后缀的,如果没有后缀的路径,则为其追加路径,如果有后缀的路径,则必须以最后一个“.”进行截取。
// 范例:文件批量命名
public static void main(String[] args) {
File file = new File("D:" + File.separator + "hello" + File.separator);// 是一个目录
long start = System.currentTimeMillis();
renameDir(file);
long end = System.currentTimeMillis();
System.out.println("本次操作花费时间:" + (end - start));
}
public static void renameDir(File file) {
if (file.isDirectory()) {// 是一个目录
File [] results = file.listFiles();// 列出子目录中的内容
if (results != null) {
for (int i = 0; i < results.length; i++) {
renameDir(results[i]);
}
}
} else {
if (file.isFile()) {// 如果是文件则必须进行重命名
String fileName = null;
if (file.getName().contains(".")) {
fileName = file.getName().substring(0, file.getName().lastIndexOf(".")) + ".txt";
} else {
fileName = file.getName() + ".txt";
}
File newFile = new File(file.getParentFile(), fileName);
file.renameTo(newFile);// 重命名
System.out.println(newFile);
}
}
}
在面试的过程中经常会出现给一个路径然后进行文件批量修改操作,那么就采用以上结构
注:上面的代码对于同一个目录下相同的文件名但是有不同的后缀修改为同一个后缀时会有部分修改失败,且程序不报错,例如hello目录下有hello.png和hello.jpg两个文件,批量修改为.txt后缀,会有一个修改成功,一个失败。