文件输入输出流主要是处理文件内容,本文用于阐述Java中如何处理磁盘中的文件及目录。
在早期的Java版本中,文件及目录的由类File进行处理,在后续的Java版本中,提供了Files和Path类,以更方便的处理文件系统中的文件和目录。
Path
Path对象可以表示一个文件对象也可以表示一个目录对象。由Paths.get(String first,String… more)获取一个Path对象。
- public static Path get(String first,String… more)
参数first为主目录,可变参数表示子目录,如Paths.get(“C:/”,“users”,“test”)表示目录C:\users\test。
Path对象常调用的方法如下:
-
public Path resolve(Path other)
如果other为绝对路径,该方法返回other否则返回由对象本身与other组合而成的Path对象。 -
public Path resolveSibling(Path other)
等价于方法调用: getParent()==null?other:resolve(other)。即如果Path父目录不存在则返回other,否则返回由对象本身与other组合而成的Path对象。 -
public Path relativize(Path other)
返回对象本身与other的相对路径表示的Path对象
import java.nio.file.Paths;
import java.nio.file.Path;
public class pathTest
{
public static void main(String[] args)
{
Path dir1=Paths.get("C:/USERS/DIR1");
Path dir2=Paths.get("C:/USERS/DIR1/Output/");
Path dir3=dir1.relativize(dir2);//dir3表示相对路径../output/
}
}
- public Path normalize()
返回的Path对象去除多余的名称元素。在很多的文件系统中.和…表示当前目录和当前目录的父目录。normalize方法会剔除路径中名称为.的子目录,如:
Path dir=Paths.get("C:/Users/./.other/this");
dir=dir.normalize();//dir对象代表的目录为:C:Users/other/this
dir=Paths.get("C:Users/this./other")
dir=dir.normalize();//dir对象代表的目录为:C:Users/this./other,此时normalize不会剔除元素.,因为该子目录名为this. 而不是.
对于路径上子目录名为…的Path对象,会剔除…及…之前除磁盘根目录的所有父目录,如
Path dir=Paths.get("C:/Users/../.other/this");
dir=dir.normalize();//dir对象代表的目录为:C:/other/this
-
public Path getFileName()
返回表示文件名或目录名的Path对象 -
public Path getParent()
返回父目录Path对象 -
public Path getRoot()
返回根目录Path对象
Files
Files对象的介绍分为两部分,第一部分介绍文件或目录创建
、复制,移动,重命名以及删除等操作;第二部分介绍如何获取文件或目录有关属性。
这里不介绍由Files进行文件读写的操作。本人更倾向于用InputStream/OutputStream以及Reader/Writer分别进行二进制和文本内容的输入输出,这里不展开介绍。
文件操作
- public static Path createFile(Path path,FileAttribute<?>…attrs)
创建一个文件 - public static Path createDirectory(Path path,FileAttribute<?>…attrs)
创建一个文件夹,如果父目录不存在,则抛出NoSuchFileException异常。如果目录已存在,则会抛出FileAlreadyExistsException异常。 - public static Path createDirectories(Path path,FileAttribute<?>…attrs)
创建由path表示的完整文件路径,不要求父目录存在 - public static Path copy(Path source,Path target,CopyOption…options)
将文件source复制到target,注意以下要点:
- 如果source为目录,则创建名为target的空目录。
- 如果source为文件,则创建名为target的文件
- 如果target文件已存在,则会抛出FileAlreadyExistsException异常。解决方法为添加参数StandardCopyOption.REPLACE_EXISTING。如下所示:
Path source=Paths.get("C:/Users/86135/Desktop/Fw2Tools/test.txt");
Path target=Paths.get("C:/tmp/test.dat");
Files.copy(source,target,StandardCopyOption.REPLACE_EXISTING);//将test.txt文件中的内容复制到文件test.dat
常见的复制选项如下:
CopyOption | Description |
---|---|
REPLACE_EXISTING | 如果文件已存在则替换已存在的文件 |
COPY_ATTRIBUTES | 复制文件或目录所有属性到目标文件或路径下 |
- public static Path move(Path source,Path target,CopyOption…options)
移动或重命名文件或目录。注意以下要点:
- move包括复制和删除两步操作,通过参数ATOMIC_MOVE 可以将整个move操作作为一个原子操作(要么移动或重命名成功,要么不做任何操作)。如下所示:
Path source=Paths.get("C:/Users/86135/Desktop/Fw2Tools/test.txt");
Path target=Paths.get("C:/tmp/");
Files.move(source,target,StandardCopyOption.ATOMIC_MOVE);
Option | Description |
---|---|
ATOMIC_MOVE | 将文件移动作为原子操作 |
- public static void delete(Path path)
删除文件或文件夹,删除文件夹时要求文件夹为空,如果目标文件或文件夹不存在则抛出异常。 - public static boolean deleteIfExists(Path path)
如果文件或文件夹存在则删除,返回值true表示删除成功,false表示删除失败
文件属性
- public static boolean exists(Path path,LinkOption…options)
文件或目录存在则返回true,否则返回false - public static boolean isHidden(Path path)
检验文件是否被隐藏 - public static boolean isReadable(Path path)
检验文件是否可读 - public static boolean isWriteable(Path path)
检验文件是否可写 - public static boolean isExecutable(Path path)
检验文件是否可执行 - public static boolean isRegularFile(Path path,LinkOption…options)
检验是否为文件 - public static boolean isDirectory(Path path,LinkOption…options)
检验是否为目录 - public static boolean isSymbolicLink(Path path)
检验是否为符号链接 - public static long size(Path path)
返回文件大小 - public static BasicFileAttributes readAttributes(Path path,BasicFileAttributes.class)
通过该方法得到BasicFileAttributes对象,通过BasicFileAttribute对象调用creationTime()、lassAccessTime()以及lastModifiedTime()方法得到的FileTime对象分别表示文件创建时间、上一次访问时间以及最后一次修改时间 - public static Path setLastModifiedTime(Path path,FileTime time)
设定文件最后一次修改时间,该访问在处理系统日志文件时经常用到
递归文件目录
以删除整个文件目录为例:
如前面介绍通过delete方法只能删除空文件夹,对于包含有文件及子目录的文件夹,需要先删除目录下所有文件再删除文件夹。调用方法walkFileTree(Path path,FileVisitor<? super Path> visitor)对文件目录进行遍历
FileVisitor中包含如下四个方法:
- public FileVisitResult visitFile(Path path,BasicFileAttributes attrs) throws IOException
访问文件时自动调用此方法,执行方法内的动作 - public FileVisitResult preVisitDirectory(Path path,BasicFileAttributes attrs) throws IOException
访问目录前调用此方法,执行方法内的动作 - public FileVisitResult visitFileFailed(Path path,IOException e) throws IOException
文件访问失败时调用此方法,执行方法内的动作 - public FileVisitResult postVisitDirectory(Path path,IOException e) throws IOException
目录访问结束后调用此方法,执行方法内的动作
上述方法返回值FileVisitResult用来决定递归程序如何继续执行:
Value | Description |
---|---|
CONTINUE | 递归程序继续执行 |
SKIP_SIBLINGS | 跳过遍历同层级的目录或文件 |
SKIP_SUBTREE | 跳过遍历子目录 |
TERMINATE | 结束遍历 |
下列程序用于删除完整的目录
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
public class TraverseDocument
{
public static void main(String[] args) throws IOException
{
Path path=Paths.get("C:/Users/86135/Desktop/Java_bk");
Files.walkFileTree(path,new SimpleFileVisitor<Path>()
{
public FileVisitResult visitFile(Path path,BasicFileAttributes attrs) throws IOException
{
Files.delete(path);//删除文件
return FileVisitResult.CONTINUE;
}
public FileVisitResult postVisitDirectory(Path path,IOException e) throws IOException
{
if(e!=null)
throw e;
Files.delete(path);//文件夹遍历结束后,删除文件夹
return FileVisitResult.CONTINUE;
}
}
);
}
}
zip文件系统
对于zip文件(即压缩文件)我们可以建立单独的文件系统来遍历压缩文件中的文件及目录
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.nio.file.FileSystems;
import java.nio.file.FileSystem;
import java.io.IOException;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.FileVisitResult;
import java.nio.file.attribute.BasicFileAttributes;
public class zipFileSystem
{
public static void main(String[] args)
{
public static void main(String[] args) throws IOException
{
FileSystem fs=FileSystems.newFileSystem(Paths.get("C:/Users/86135/Desktop/hahhahha.zip"),null);
Files.walkFileTree(fs.getPath("/"),new SimpleFileVisitor<Path>()
{
public FileVisitResult visitFile(Path path,BasicFileAttributes attrs) throws IOException
{
System.out.println(path.getFileName());
return FileVisitResult.CONTINUE;
}
public FileVisitResult preVisitDirectory(Path path,BasicFileAttributes attrs) throws IOException
{
if(path.getFileName()!=null)//避免输出根目录"/"
System.out.println(path.getFileName());
return FileVisitResult.CONTINUE;
}
}
);
}
}
}