背景介绍
本文主要介绍 java.io.File类的使用,包含File类的构造方法及File类中的常用方法
File类的属性
File类提供了四个静态属性
修饰符及类型 | 属性 | 说明 |
---|---|---|
static String | pathSeparator | 依赖于系统的路径分隔符,String类型的表示,linux上为: windows上为; |
static char | pathSeparatorChar | 依赖于系统的路径分隔符,char类型的表示,linux上为: windows上为; |
static String | separator | 依赖于系统的默认名称分隔符,String类型的表示,linux上为/ windows上为\\ |
static char | separatorChar | 依赖于系统的默认名称分隔符,char类型的表示,linux上为/ windows上为\\ |
separator
public static final String separator
与系统有关的默认名称分隔符。此字段被初始化为包含系统属性 file.separator 值的第一个字符。在 UNIX 系统上,此字段的值为 ‘/’;在 Microsoft Windows 系统上,它为 ‘/’。
pathSeparator
public static final String pathSeparator
与系统有关的路径分隔符。此字段被初始为包含系统属性 path.separator 值的第一个字符。此字符用于分隔以路径列表 形式给定的文件序列中的文件名。在 UNIX 系统上,此字段为 ‘:’;在 Microsoft Windows 系统上,它为 ‘;’。
pathSeparator与separator的区别
File.pathSeparator指的是分隔连续多个路径字符串的分隔符,例如:
java -cp test.jar;abc.jar HelloWorld
就是指“;”
File.separator才是用来分隔同一个路径字符串中的目录的,例如:
C:/Program Files/Common Files
就是指“/”
File类的构造方法
方法 | 说明 |
---|---|
File(String pathname) | 通过路径名创建一个新的File实例 |
File(String parent, String child) | 根据父目录+子文件路径创建一个新的File实例,父目录用路径表示 |
File(File parent, String child) | 根据父目录+子文件路径创建一个新的File实例,父目录用文件表示 |
File(URI uri) | 根据指定的file:URI转换成一个抽象路径名来创建一个新的File实例 |
注意:调用构造方法的时候还没有创建出文件或文件目录, 仅返回File实例对象
File(String pathname)
该构造方法是通过将给定路径名字字符串转化为抽象路径名来创建一个File的实例;
其中,pathname 表示路径名称,可以是文件或者文件夹;
//两种写法都对,不同的地方在于Test1是文件,Test2是文件夹。
//注意:调用构造方法的时候还没有创建出文件或文件目录
File file1=new File("C:\\export\\Test1.text");
File file2=new File("C:\\export\\Test2");
try {
file1.createNewFile();
file2.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
File(String parent, String child)
该构造方法是根据定义的父路径和子路径字符串(包含文件名)创建一个新的File对象;(父路径和子路径的概念)
File file1=new File("C:/","/export/Tes1.text");
File file2=new File("C:/export","Tes1.text");
File(File parent, String child)
该方法时根据parent抽象路径和child路径名字来创建一个新的File对象。
File file1=new File("E:/Tes1");
File file2=new File(file1,"Tes2.text");
File(URI uri)
通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例。(URL和URI的区别)
public static void main(String[] args) {
try {
File file = new File(new URI("file:///c:/a.bat"));
System.out.println(file.getName());
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
执行结果:
a.bat
File类的常用方法
返回值类型 | 方法 | 作用 |
---|---|---|
String | getName() | 返回由此抽象路径名表示的文件或目录的名称。 |
String | getParent() | 获取文件的父路径(字符串),如果此路径名没有指定父目录,则返回 null |
File | getParentFile() | 获取文件的父路径(抽象路径名),如果此路径名没有指定父目录,则返回 null |
boolean | canRead() | 判断应用程序是否可以读取此抽象路径名表示的文件。 |
canWrite() | boolean | 判断应用程序是否可以修改此抽象路径名表示的文件。 |
boolean | canExecute() | 程序是否可以执行由抽象路径名表示的指定文件。如果文件路径存在并且允许应用程序执行文件,则此方法将返回true。否则它将返回false。 |
boolean | exists() | 判断此抽象路径名表示的文件或目录是否存在。 |
long | length() | 判断文件的长度(字节),可以用来判断文件是否是空文件 |
boolean | isAbsolute() | 判断此抽象路径名是否为绝对路径名。 |
String | getAbsolutePath() | 获取文件的绝对路径(字符串) |
File | getAbsoluteFile() | 获取文件的绝对路径(抽象路径名) |
boolean | isFile() | 判断此抽象路径名表示的文件是否是一个标准文件。 |
boolean | isDirectory() | 判断此抽象路径名表示的文件是否是一个目录。 |
boolean | isHidden() | 判断文件是否是隐藏文件 |
long | lastModified() | 返回文件最后修改的时间 |
boolean | renameTo(File dest) | 文件重命名 |
boolean | delete() | 删除此抽象路径名表示的文件或目录。 |
void | deleteOnExit() | 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。 |
String[] | list() | 返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。 |
String[] | list(FilenameFilter filter) | 返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。 |
File[] | listFiles() | 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。 |
File[] | listFiles(FileFilter filter) | 返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。 |
boolean | mkdir() | 创建此抽象路径名指定的目录。(只能创建一级文件夹) |
boolean | mkdirs() | 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。(可以创建多级文件夹) |
boolean | setLastModified(long time) | 设置由此抽象路径名所指定的文件或目录的最后一次修改时间。 |
boolean | setReadOnly() | 标记此抽象路径名指定的文件或目录,以便只可对其进行读操作。 |
File | createTempFile(String prefix, String suffix, File directory) | 在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。 |
File | createTempFile(String prefix, String suffix) | 在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。 |
int | compareTo(File pathname) | 按字母顺序比较两个抽象路径名。 |
int | compareTo(Object o) | 按字母顺序比较抽象路径名与给定对象。 |
常用方法的使用:
public class Test {
public static void main(String[] args) throws IOException {
//绝对路径
File file=new File("d:/test.txt");
System.out.println(file.getParent());// 获取到文件的父目录文件路径
System.out.println(file.getName());// 获取到文件名
System.out.println(file.getPath());// 获取到文件路径(构造 file 的时候指定的路径)
System.out.println(file.getAbsolutePath());// 获取到绝对路径
System.out.println(file.getCanonicalPath());// 获取到绝对路径.[需要处理异常]
System.out.println("====================");
//相对路径
File file1 = new File("./test.txt");
System.out.println(file1.getParent());// 获取到文件的父目录文件路径
System.out.println(file1.getName());// 获取到文件名
System.out.println(file1.getPath());// 获取到文件路径(构造 file 的时候指定的路径)
System.out.println(file1.getAbsolutePath());// 获取到绝对路径
System.out.println(file1.getCanonicalPath());// 获取到绝对路径.[需要处理异常]
}
}
执行结果:
d:\
test.txt
d:\test.txt
d:\test.txt
D:\test.txt
====================
.
test.txt
.\test.txt
C:\demo\.\test.txt
C:\demo\test.txt
File进阶
获取指定目录下符合条件的文件
需求:获取指定目录下的所有.txt格式的文件名
说明:以下代码仅讲解获取指定目录下的txt文件(不包含子目录下的文件,如abc目录下还有c.txt、d.txt,但在以下方法中不会获取到,如有这种需求需要修改方法)
方式一:借助File提供的list()或listFiles()方法
File dir=new File("C:\\fileTest");
String[] fileList = dir.list();
File[] files = dir.listFiles( );
System.out.println("c盘fileTest目录下的文件夹或文件为:" );
for (File file : files) {
System.out.println(" |--" + file );
}
System.out.println("c盘fileTest目录下的txt文件为:");
for(File file : files){
if(file.isFile() && file.getName().endsWith(".txt")){
System.out.println(" |--" + file );
}
}
执行结果:
c盘fileTest目录下的文件夹或文件为:
|--C:\fileTest\a.txt
|--C:\fileTest\abc
|--C:\fileTest\b.txt
|--C:\fileTest\c.xlsx
c盘fileTest目录下的txt文件为:
|--C:\fileTest\a.txt
|--C:\fileTest\b.txt
**方式二:**使用FileFilter或FilenameFilter接口操作某一个目录
public class Test {
public static void main(String[] args) {
File dir=new File("C:\\fileTest");
File[] files = dir.listFiles( );
System.out.println("c盘fileTest目录下的文件夹或文件为:" );
for (File file : files) {
System.out.println(" |--" + file );
}
//1.
String[] s1 = dir.list(new FilenameFilter( ) {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".txt");
}
});
System.out.println("用FilenameFilter(返回的是String[] s)方法筛选出来的.txt文件为:" );
for (String s : s1) {
System.out.println(" |--" + s);
}
//2.
File[] files2 = dir.listFiles(new FilenameFilter( ) {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".txt");
}
});
System.out.println("用FilenameFilter(返回的是File[] file)方法筛选出来的.txt文件为:" );
for (File file : files2) {
System.out.println(" |--" + file );
}
//3.
File[] files3 = dir.listFiles(new FileFilter( ) {
@Override
public boolean accept(File pathname) {
return pathname.getName( ).endsWith(".txt");
}
});
System.out.println("用FileFilter(返回的是File[] file)方法筛选出来的.txt文件为:" );
for (File file : files3) {
System.out.println(" |--" + file );
}
System.out.println("-------------用lambda方法--------------" );
//1.
String[] s2 = dir.list((File dir1, String name) -> name.endsWith(".txt"));
System.out.println("用lambda方法、返回String[]的(new FilenameFilter()中的File dir, String name参数)筛选出来的.txt文件为:" );
for (String s : s2) {
System.out.println(" |--" + s);
}
//2.
File[] files4 = dir.listFiles((File dir1, String name) -> name.endsWith(".txt"));
System.out.println("用lambda方法、返回File[]的(new FilenameFilter()中的File dir, String name参数)筛选出来的.txt文件为:" );
for (File file : files4) {
System.out.println(" |--" + file );
}
//3.
File[] files5 = dir.listFiles((pathname -> pathname.getName( ).endsWith(".txt")));
System.out.println("用lambda方法、(new FileFilter()中的pathname参数)筛选出来的.txt文件为:" );
for (File file : files5) {
System.out.println(" |--" + file );
}
}
}
执行结果
c盘fileTest目录下的文件夹或文件为:
|--C:\fileTest\a.txt
|--C:\fileTest\abc
|--C:\fileTest\b.txt
|--C:\fileTest\c.xlsx
用FilenameFilter(返回的是String[] s)方法筛选出来的.txt文件为:
|--a.txt
|--b.txt
用FilenameFilter(返回的是File[] file)方法筛选出来的.txt文件为:
|--C:\fileTest\a.txt
|--C:\fileTest\b.txt
用FileFilter(返回的是File[] file)方法筛选出来的.txt文件为:
|--C:\fileTest\a.txt
|--C:\fileTest\b.txt
-------------用lambda方法--------------
用lambda方法、返回String[]的(new FilenameFilter()中的File dir, String name参数)筛选出来的.txt文件为:
|--a.txt
|--b.txt
用lambda方法、返回File[]的(new FilenameFilter()中的File dir, String name参数)筛选出来的.txt文件为:
|--C:\fileTest\a.txt
|--C:\fileTest\b.txt
用lambda方法、(new FileFilter()中的pathname参数)筛选出来的.txt文件为:
|--C:\fileTest\a.txt
|--C:\fileTest\b.txt
mkdir()与mkdirs()的区别
- mkdirs()可以建立多级文件夹
- mkdir()只会建立一级的文件夹
new File("/tmp/one/two/three").mkdirs();
执行后, 会建立tmp/one/two/three四级目录
new File("/tmp/one/two/three").mkdir();
则不会建立任何目录, 因为找不到/tmp/one/two目录, 结果返回false
renameTo方法
重新命名此抽象路径名表示的文件。
此方法返回boolean值,表示重命名成功或失败,所以在开发过程中一定要注意进行判断
/**
*
重新命名此抽象路径名表示的文件。
此方法行为的许多方面都是与平台有关的:重命名操作无法将一个文件从
一个文件系统移动到另一个文件系统,
该操作不是不可分的,如果已经存在具有目标抽象路径名的文件,
那么该操作可能无法获得成功。应该始终检查返回值,以确保重命名操作成功。
参数:
dest - 指定文件的新抽象路径名
返回:
当且仅当重命名成功时,返回 true;否则返回 false
抛出:
SecurityException - 如果存在安全管理器,且其 SecurityManager.checkWrite(java.lang.String) 方法拒绝对原路径名和新路径名进行写访问
NullPointerException - 如果参数 dest 为 null
*/
public boolean renameTo(File dest) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(path);
security.checkWrite(dest.path);
}
if (dest == null) {
throw new NullPointerException();
}
if (this.isInvalid() || dest.isInvalid()) {
return false;
}
return fs.rename(this, dest);
}
第一种场景:同一路径下文件重命名【文件重命名】
说明:将C:\test\1.txt下的 1.txt 重名为2.txt !
如果test路径下1.txt 不存在,那么返回false。
如果test路径下2.txt已存在, 那么返回false。
File oldFile = new File("C:\\test\\1.txt");
File newFile = new File("C:\\test\\2.txt");
System.out.println(oldFile.renameTo(newFile));//true
第二种场景:将文件从一个路径移动另一个路径下,并且移动的文件进行重命名【文件移动重命名】
说明:将C:\test\1.txt下的 1.txt 移动到E:\demo\路径下,并重名命名为2.txt .
其中 E:\demo必须要存在,否则返回false ; E:\demo\2.txt不能存在,否则返回false。
File oldFile = new File("C:\\test\\1.txt");
File newFile = new File("E:\\demo\\2.txt");
System.out.println(oldFile.renameTo(newFile));//true
第三种场景:修改文件夹的名称,文件夹里面没有文件的时候修改成功
File oldFile = new File("C:\\test");
File newFile = new File("C:\\test1");
System.out.println(oldFile.renameTo(newFile));//true
复制文件 FileUtils.copyFile(final File srcFile, final File destFile)
apache commons-io包中提供了复制文件的方法, 需要注意的是该方法会把源文件复制一份到指目标文件,
如果目标文件不存在,将创建保存该文件的目录。如果目标文件存在,则此方法将覆盖它。
导入依赖包
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
FileUtils.copyFile 源码
/**
* 将文件复制到保留文件日期的新位置。
*
* 此方法将指定源文件的内容复制到指定目标文件。`如果目标文件不存在,将创建保存该文件的目录。如果目标文件存在,则此方法将覆盖它。`
*
* 注意:此方法尝试使用file.setlastmedited(long)保留文件的上次修改日期/时间,但不能保证操作会成功。如果修改操作失败,则不提供任何指示。
*/
public static void copyFile(final File srcFile, final File destFile) throws IOException {
copyFile(srcFile, destFile, true);
}
代码示例
File oldfile = new File("d:/test/a.jpg");
File newfile1 = new File("d:/test/b.jpg");
FileUtils.copyFile(oldfile,newfile1); // a.jpg不变,新增一个b.jpg
createTempFile(String prefix, String suffix,File directory) 创建临时文件
根据prefix+
随机数
+suffix生成空的临时文件。一般与deleteOnExit配合使用,若临时文件使用完之后想要清理,可以用deleteOnExit在虚拟机关闭前清理临时文件;或者用delete方法直接清除文件
/**
* 使用给定前缀和后缀字符串以生成其名称。如果此方法成功返回,则保证:
*
* <ol>
* <li> 由返回的抽象路径名表示的文件不存在在调用此方法之前,以及
* <li> 此方法及其任何变体都不会返回相同的结果在虚拟机的当前调用中再次抽象路径名机器
* </ol>
*
*此方法仅提供临时文件设施的一部分。安排要自动删除由该方法创建的文件,请使用{@link#deleteOnExit}方法。
*
* prefix参数必须至少包含三个字符。suffix参数可以是null,在这种情况下将使用后缀“.tmp”。
*
* 要创建新文件,前缀和后缀可以首先是调整以适应底层平台的限制。如果
* 前缀太长,它将被截断,但它的前三个将始终保留字符。如果后缀太长,则也将被截断,但如果
* 它以句点字符开头(<code>'.'</code>)然后是句点和前三个字符将始终保留它。一旦这些调整
* 完成使新文件的名称将通过连接前缀、五个或更多内部生成的字符以及后缀。
*
* 如果directory参数为null,则将使用依赖于系统的默认临时文件目录。这个
* 默认临时文件目录由系统属性指定java.io.tmpdir。在UNIX系统上
* 属性通常是“/tmp”或”/var/tmp“;在Windows系统通常是“C:\\WINNT\\TEMP”
*
* @param prefix `用于生成文件的前缀字符串名称; 长度必须至少为三个字符`
*
* @param suffix `生成文件时使用的后缀字符串名称; 可以是null,在这种情况下将使用后缀“.tmp”`
*
* @param directory `创建文件的目录。若为null,则使用默认临时路径;若不为null,则目录必须是已存在的,否则会抛出IOException `
*
* @throws IllegalArgumentException 如果prefix参数包含少于三个字符
*
* @throws IOException 无法创建文件
*
* @throws SecurityException 如果java.lang.SecurityManager.checkWrite(java.lang.String) 该方法不允许创建文件
*/
public static File createTempFile(String prefix, String suffix,
File directory)
throws IOException
{
if (prefix.length() < 3)
throw new IllegalArgumentException("Prefix string too short");
if (suffix == null)
suffix = ".tmp";
File tmpdir = (directory != null) ? directory
: TempDirectory.location();
SecurityManager sm = System.getSecurityManager();
File f;
do {
f = TempDirectory.generateFile(prefix, suffix, tmpdir);
if (sm != null) {
try {
sm.checkWrite(f.getPath());
} catch (SecurityException se) {
// don't reveal temporary directory location
if (directory == null)
throw new SecurityException("Unable to create temporary file");
throw se;
}
}
} while ((fs.getBooleanAttributes(f) & FileSystem.BA_EXISTS) != 0);
if (!fs.createFileExclusively(f.getPath()))
throw new IOException("Unable to create temporary file");
return f;
}
测试demo
//获取系统临时目录
String tmpdir = System.getProperty("java.io.tmpdir");
System.out.println(tmpdir);
File file = File.createTempFile("测试图片",".jpg");
System.out.println(file.getAbsolutePath());
执行结果:
C:\Users\ADMINI~1\AppData\Local\Temp\
C:\Users\ADMINI~1\AppData\Local\Temp\测试图片2516854975283426092.jpg
delete()与deleteOnExit()的区别
File类的两个方法delete和deleteOnExit的作用都是删除文件,但两者是有差别的。
delete:删除File对象表示的文件或目录,如果表示的是目录,需要保证目录是空的,否则无法删除。若成功删除返回true,否则返回false。
deleteOnExit:当虚拟机终止时,删除File对象表示的文件或目录,如果表示的是目录,需要保证目录是空的,否则无法删除,无返回值。
可以看出两个方法的区别是,delete是立即执行删除,而deleteOnExit是程序退出虚拟机时才会删除。
但是实际中使用deleteOnExit()出现了未删除临时文件的情况,可能是因为程序结束时jvm并未退出,造成deleteOnExit()没有触发。
常见问题
new File(pathname) 会创建文件么?
如下代码,我们在调用new File(pathname)方法后会不会创建该文件呢?
File file1=new File("C:\\export\\Test1.text");
File file2=new File("C:\\export\\Test2");
结论:调用File的构造方法并不会创建出文件并且也不会校验文件路径是否合法,只有当显示调用createNewFile()方法后才会创建文件。目录的话需要调用mkdir()或mkdirs()方法才会创建目录。
FileOutputStream会自动创建文件吗?
- 使用FileOutputStream 的时候,如果目标文件不存在,那么会自动创建目标文件对象。
- 使用FileOutputStream的时候,如果目标文件已存在,那么会先清空目标文件中的数据,然后再写入数据。
- 创建文件输入流写入由指定的File对象表示的文件。如果第二个参数是true,则字节将被写入文件的末尾而不是开头。如果文件存在但是是一个目录而不是常规文件,不存在但不能创建,或者由于任何其他原因无法打开,那么将抛出一个FileNotFoundException。
public static void main(String[] args) {
String filepath = "C:\\test\\aa.txt";
String data = "hello";
byte[] buf = data.getBytes();
try {
FileOutputStream fileOutputStream = new FileOutputStream(filepath);
//new FileOutputStream(String name, boolean append)
fileOutputStream.write(buf);
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
注意:用FileOutputStream创建文件时,文件路径一定要存在,如上面的C:\\test路径需要存在,否则会抛出异常