File
字数: 0 字 时长: 0 分钟
在 IO 操作中,文件操作相对来说比较复杂,但也是使用频率最高的一部分。几乎所有项目中都会有一个叫做 FileUtil 或者 FileUtils 的工具类。
java.io.File 类是专门对文件进行操作的类,需要注意:
File只能对文件本身进行操作,不能对文件内容进行读写。如果想要操作文件内容,需要借助输入流和输出流。
File 类是文件和目录的抽象表示,主要用于文件和目录的创建、查找、删除等操作。
怎么理解这两句话?其实很简单:
- 第一,
File和流无关,File类本身不能对文件内容进行读和写,也就是不能完成输入和输出。 - 第二,
File可以表示/文件目录1,也可以表示/文件目录1/文件.txt。前者是目录(Directory),后者是文件(File),File类都可以对它们进行操作。
1. File 构造方法
在 Java 中,一切皆对象,File 类也不例外。要使用 File,首先需要通过构造方法创建对应的对象。
比较常用的构造方法有三个:
File(String pathname):通过给定的路径创建新的File实例。File(String parent, String child):通过父路径字符串和子路径字符串创建新的File实例。File(File parent, String child):通过父路径 File 对象和子路径字符串创建新的File实例。
代码如下:
// 文件路径名
String path = "/Users/mac/Documents/CompanyCode2/123.txt";
File file1 = new File(path);
// 文件路径名
String path2 = "/Users/mac/Documents/CompanyCode2/1/2.txt";
File file2 = new File(path2);
// 通过父路径和子路径字符串
String parent = "/Users/mac/Documents/CompanyCode2/aaa";
String child = "bbb.txt";
File file3 = new File(parent, child);
// 通过父级 File 对象和子路径字符串
File parentDir = new File("/Users/mac/Documents/CompanyCode2/aaa");
String child2 = "bbb.txt";
File file4 = new File(parentDir, child2);macOS 和 Linux 路径使用正斜杠 / 作为路径分隔符,而 Windows 路径使用反斜杠 \ 作为路径分隔符。
所以在遇到路径分隔符的时候,不要直接固定写 / 或者 \。
Java 提供了一个跨平台的路径分隔符:
File.separator这个属性会根据当前操作系统自动返回对应的路径分隔符。
File 类还需要注意两点:
- 一个
File对象用于表示硬盘中的文件或目录。 File的构造方法不会检查文件或目录是否真实存在,因此无论对应路径是否存在,都不影响File对象的创建。
2. File 常用方法
File 的常用方法主要可以分为:
File 常用方法
├── 获取功能
├── 绝对路径和相对路径
├── 判断功能
├── 创建和删除
├── 目录遍历
└── 递归遍历2.1 获取功能的方法
常用方法:
getAbsolutePath():返回此File的绝对路径。getPath():返回创建File对象时使用的路径。getName():返回文件名或目录名。length():返回文件长度,以字节为单位。
测试代码如下,具体路径以自己的电脑为准:
public class CommonMethodsForFile {
public static void main(String[] args) {
File f =
new File(
"/Users/mac/Documents/CompanyCode2/logfile.log"
);
System.out.println(
"文件绝对路径:" + f.getAbsolutePath()
);
System.out.println(
"文件构造路径:" + f.getPath()
);
System.out.println(
"文件名称:" + f.getName()
);
System.out.println(
"文件长度:" + f.length() + "字节"
);
File f2 =
new File(
"/Users/mac/Documents/CompanyCode2/"
);
System.out.println(
"目录绝对路径:" + f2.getAbsolutePath()
);
System.out.println(
"目录构造路径:" + f2.getPath()
);
System.out.println(
"目录名称:" + f2.getName()
);
System.out.println(
"目录长度:" + f2.length()
);
}
}需要注意:
length()主要用于获取文件的长度。当File对象表示目录时,返回值通常没有实际使用意义。
结果:
文件绝对路径:/Users/mac/Documents/CompanyCode2/logfile.log
文件构造路径:/Users/mac/Documents/CompanyCode2/logfile.log
文件名称:logfile.log
文件长度:43897字节
目录绝对路径:/Users/mac/Documents/CompanyCode2
目录构造路径:/Users/mac/Documents/CompanyCode2
目录名称:CompanyCode2
目录长度:1282.2 绝对路径和相对路径
绝对路径是从文件系统根目录开始的完整路径,用于描述文件或目录在文件系统中的确切位置。
Windows 中的绝对路径通常以盘符开始,例如:
C:\Program Files\Java\jdk1.8.0_291\bin\java.exemacOS 和 Linux 中的绝对路径通常以 / 开始,例如:
/usr/local/bin/python3相对路径是相对于当前工作目录的路径,用于描述文件或目录与当前工作目录之间的位置关系。
例如:
config/config.properties如果当前工作目录是:
/Users/mac/project那么:
config/config.properties实际表示:
/Users/mac/project/config/config.properties注意:
- 在 Windows 操作系统中,文件系统通常默认不区分大小写。例如
example.txt和Example.txt通常表示同一个文件,但 Windows 也提供了区分大小写的相关配置。 - 在 macOS 和 Linux 等 Unix 系统中,文件系统是否区分大小写与具体文件系统和配置有关,使用时需要注意文件名大小写。
// 绝对路径示例
File absoluteFile =
new File(
"/Users/mac/Documents/CompanyCode2/logfile.log"
);
System.out.println(
"绝对路径:" + absoluteFile.getAbsolutePath()
);
// 相对路径示例
File relativeFile =
new File(
"CompanyCode2/logfile.log"
);
System.out.println(
"相对路径:" + relativeFile.getPath()
);2.3 判断功能的方法
常用的判断方法:
exists():判断文件或目录是否存在。isDirectory():判断是否为目录。isFile():判断是否为文件。
代码如下:
File file =
new File(
"/Users/mac/Documents/CompanyCode2/logfile.log"
);
// 判断文件或目录是否存在
if (file.exists()) {
System.out.println("文件或目录存在");
} else {
System.out.println("文件或目录不存在");
}
// 判断是否是目录
if (file.isDirectory()) {
System.out.println("是目录");
} else {
System.out.println("不是目录");
}
// 判断是否是文件
if (file.isFile()) {
System.out.println("是文件");
} else {
System.out.println("不是文件");
}结果:
File file =
new File(
"/Users/mac/Documents/CompanyCode2/logfile.log"
);
// 判断文件或目录是否存在
if (file.exists()) {
System.out.println("文件或目录存在");
} else {
System.out.println("文件或目录不存在");
}
// 判断是否是目录
if (file.isDirectory()) {
System.out.println("是目录");
} else {
System.out.println("不是目录");
}
// 判断是否是文件
if (file.isFile()) {
System.out.println("是文件");
} else {
System.out.println("不是文件");
}2.4 创建、删除功能的方法
常用方法:
createNewFile():文件不存在时创建一个新的空文件并返回true;文件已经存在时不创建并返回false。delete():删除文件或目录。如果是目录,只有目录为空时才能删除。mkdir():创建一级目录,如果父目录不存在则创建失败。返回true表示创建成功,返回false表示创建失败。mkdirs():可以创建多级目录,如果父目录不存在,会一并创建。返回true表示创建成功,返回false表示创建失败或者目录已经存在。
开发中一般使用:
mkdirs()方法测试:
// 创建文件
File file2 =
new File(
"/Users/mac/Documents/CompanyCode2/example/test.txt"
);
if (file2.createNewFile()) {
System.out.println(
"创建文件成功:" + file2.getAbsolutePath()
);
} else {
System.out.println(
"创建文件失败:" + file2.getAbsolutePath()
);
}
// 删除文件
if (file2.delete()) {
System.out.println(
"删除文件成功:" + file2.getAbsolutePath()
);
} else {
System.out.println(
"删除文件失败:" + file2.getAbsolutePath()
);
}
// 创建多级目录
File directory =
new File(
"/Users/username/example/subdir1/subdir2"
);
if (directory.mkdirs()) {
System.out.println(
"创建目录成功:" + directory.getAbsolutePath()
);
} else {
System.out.println(
"创建目录失败:" + directory.getAbsolutePath()
);
}2.5 目录的遍历
常用方法:
String[] list():返回一个String数组,表示该目录中的所有子文件或子目录名称。File[] listFiles():返回一个File数组,表示该目录中的所有子文件或子目录。
File directory2 =
new File(
"/Users/mac/Documents/LearnCode/framework-learn-javase"
);
// 列出目录下的文件名
String[] files =
directory2.list();
System.out.println(
"目录下的文件名:"
);
for (String file3 : files) {
System.out.println(file3);
}
// 列出目录下的文件和子目录
File[] filesAndDirs =
directory2.listFiles();
System.out.println(
"目录下的文件和子目录:"
);
for (File fileOrDir : filesAndDirs) {
if (fileOrDir.isFile()) {
System.out.println(
"文件:" + fileOrDir.getName()
);
} else if (fileOrDir.isDirectory()) {
System.out.println(
"目录:" + fileOrDir.getName()
);
}
}listFiles() 在获取指定目录下的文件或子目录时,需要注意:
- 指定的目录必须存在。
- 指定的路径必须是目录,否则
listFiles()可能返回null,后续直接遍历容易引发NullPointerException。
2.6 递归遍历
直接看代码:
public static void main(String[] args) {
File directory =
new File(
"/Users/mac/Documents/LearnCode/framework-learn-javase"
);
// 递归遍历目录下的文件和子目录
traverseDirectory(directory);
}
public static void traverseDirectory(
File directory
) {
// 列出目录下的所有文件和子目录
File[] filesAndDirs =
directory.listFiles();
// 遍历每个文件和子目录
for (
File fileOrDir : filesAndDirs
) {
if (
fileOrDir.isFile()
) {
// 如果是文件,输出文件名
System.out.println(
"文件:" + fileOrDir.getName()
);
} else if (
fileOrDir.isDirectory()
) {
// 如果是目录,输出目录名并继续递归
System.out.println(
"目录:" + fileOrDir.getName()
);
traverseDirectory(
fileOrDir
);
}
}
}3. RandomAccessFile
RandomAccessFile 是 Java 中一个比较特殊的类,它既可以读取文件,也可以写入文件。
与 FileInputStream、FileOutputStream 等普通 IO 类不同,RandomAccessFile 可以将文件指针移动到文件中的指定位置,再从该位置开始读取或者写入数据。
因此,它比较适合需要对文件进行随机访问的场景,例如数据库系统。
下面是一个 RandomAccessFile 的示例,包括文件的写入和读取:


3.1 构造方法
RandomAccessFile 主要有两个构造方法:
RandomAccessFile(File file, String mode):使用给定的File对象和访问模式创建新的RandomAccessFile实例。RandomAccessFile(String name, String mode):使用给定的文件名和访问模式创建新的RandomAccessFile实例。
访问模式 mode 的值可以是:
"r":以只读模式打开文件,调用任何write方法都会导致IOException。"rw":以读写模式打开文件,如果文件不存在则创建。"rws":以读写模式打开文件,并要求对文件内容或元数据的每次更新同步写入底层存储设备。"rwd":与"rws"类似,但主要要求文件内容的更新同步写入,元数据更新可以延迟。
3.2 主要方法
常用方法:
long getFilePointer():返回文件指针的当前位置。long length():返回文件长度。int read():读取一个字节的数据。int read(byte[] b):读取数据并保存到指定字节数组中。int read(byte[] b, int off, int len):从文件读取数据并保存到指定字节数组,从off开始,最多读取len个字节。String readLine():从文件中读取一行文本。readUTF():读取由writeUTF()写入的字符串。void seek(long pos):将文件指针移动到文件中的pos位置。void write(byte[] b):将指定字节数组写入文件。void write(byte[] b, int off, int len):将指定字节数组中从off开始的len个字节写入文件。void write(int b):向文件写入一个字节。writeUTF(String str):以writeUTF()所使用的格式将字符串写入文件。
其中:
writeUTF()
↓
写入长度信息 + 字符串数据
readUTF()
↓
读取长度信息 + 字符串数据因此,使用 readUTF() 读取时,需要保证对应的数据是通过 writeUTF() 写入的。
再来看一个示例,结合前面的讲解,就可以掌握 RandomAccessFile 的基本使用。
public class RandomAccessFileDemo2 {
public static void main(String[] args) {
File file =
new File(
"logs/javabetter/nihao.txt"
);
try (
RandomAccessFile raf =
new RandomAccessFile(
file,
"rw"
)
) {
// 写入文件
raf.writeUTF(
"Hello, kerwim!"
);
// 将文件指针移动到文件开头
raf.seek(0);
// 读取文件内容
String content =
raf.readUTF();
System.out.println(
"内容: " + content
);
} catch (
IOException e
) {
e.printStackTrace();
}
}
}在这个示例中,首先创建了一个名为 nihao.txt 的文件对象,然后使用 RandomAccessFile 以读写模式打开这个文件。
接着使用:
writeUTF("Hello, kerwim!");将字符串写入文件。
然后通过:
seek(0);把文件指针移动到文件开头,再使用:
readUTF();读取文件内容。
最终输出:
Hello, kerwim!最后使用 try-with-resources,确保 RandomAccessFile 在操作完成后被正确关闭。
4. Apache FileUtils 类
FileUtils 是 Apache Commons IO 中提供的文件操作工具类,提供了更加方便的方法来操作文件和目录。
4.1 复制文件或目录
File srcFile =
new File(
"path/to/src/file"
);
File destFile =
new File(
"path/to/dest/file"
);
// 复制文件
FileUtils.copyFile(
srcFile,
destFile
);
// 复制目录
FileUtils.copyDirectory(
srcFile,
destFile
);4.2 删除文件或目录
File file =
new File(
"path/to/file"
);
// 删除文件或目录
FileUtils.delete(file);需要注意的是,如果要删除一个非空目录,需要先删除目录中的所有文件和子目录。
4.3 移动文件或目录
File srcFile =
new File(
"path/to/src/file"
);
File destFile =
new File(
"path/to/dest/file"
);
// 移动文件或目录
FileUtils.moveFile(
srcFile,
destFile
);4.4 查询文件或目录的信息
File file =
new File(
"path/to/file"
);
// 获取文件或目录的修改时间
Date modifyTime =
FileUtils.lastModified(file);
// 获取文件或目录的大小
long size =
FileUtils.sizeOf(file);
// 获取文件或目录的扩展名
String extension =
FileUtils.getExtension(
file.getName()
);5. Hutool FileUtil 类
FileUtil 是 Hutool 工具包中的文件操作工具类,提供了一系列简单易用的文件操作方法,可以帮助 Java 开发者快速完成文件相关的操作。
FileUtil 主要包含以下几类操作:
- 文件操作:文件或目录的新建、删除、复制、移动、改名等。
- 文件判断:判断文件或目录是否非空、是否为目录、是否为文件等。
- 绝对路径:针对 ClassPath 中的文件转换为绝对路径文件。
- 文件名:获取主文件名、扩展名等。
- 读操作:包括
getReader、readXXX等操作。 - 写操作:包括
getWriter、writeXXX等操作。
下面是 FileUtil 中一些常用的方法。
5.1 copyFile
复制文件,将指定的源文件复制到目标文件中。
File dest =
FileUtil.file(
"FileUtilDemo2.java"
);
FileUtil.copyFile(
file,
dest
);5.2 move
移动文件或目录,将指定的源文件或目录移动到目标位置。
FileUtil.move(
file,
dest,
true
);5.3 del
删除指定的文件或目录。
FileUtil.del(file);5.4 rename
将指定的文件或目录重命名为新的名称。
FileUtil.rename(
file,
"FileUtilDemo3.java",
true
);5.5 readLines
读取文件中的每一行数据。
FileUtil.readLines(
file,
"UTF-8"
).forEach(
System.out::println
);更多方法,可以去看一下 Hutool 的源码,里面有非常多实用的方法。多看看,绝对能提升不少编程水平。