Java7中那些新特性 - 4 (文件操作篇)
程序员文章站
2022-03-16 13:07:27
...
以前两篇博客都是关于文件路径和文件信息,今天我们来看看Java7中提供了哪些新的API,可以让我们非常简单的复制、移动和删除文件以及路径。
首先来说如何创建一个新的文件夹和文件,直接上例子。
上例中,在调用createFile方法时,如果想要创建的文件已经存在,FileAlreadyExistsException会被抛出。createFile和createDirectory这个两个方法都是原子性的,即要不整个操作都能成功或者整个操作都失败。
复制一个文件同样非常简单,Files的copy方法就可以实现。在复制文件时,我们可以对复制操作加一个参数来指明具体如何进行复制。java.lang.enum.StandardCopyOption这个枚举可以用作参数传递给copy方法。
此外copy方法还支持输入输出流作为参数,以来复制非文件系统的信息。而复制文件夹的操作也并不复杂,如下例。
在我们做开发工作的时候,有时需要用到一个临时文件做介质,这些临时文件不需要被持久的保存下来,当程序结束或者一个方法处理完,就可以被删除掉了。Java7中提供了对临时文件良好的操作方法。
我们可以通过给createTempDirectory和createTempFile方法传递不同的参数来指定临时文件的前缀和后缀,具体使用方式请参照JDK文档。
Files类还提供了一些方法,方便我们修改那些文件本身和时间相关的属性。
当要修改文件所属用户的时候,运行Java程序的用户需要有特定的权限,这里对不同操作系统的权限控制方式不做介绍,大家可以自己学习一下。下例中的用户JavaUser必须是存在在系统中的,否则会抛UserPrincipalNotFoundException异常。
移动文件有一些地方需要注意,首先是如果移动一个文件夹,文件夹和其子文件夹都会被移动,跨磁盘移动的文件夹时,目标文件夹必须是空的,否则会有DirectoryNotEmptyException异常抛出。
如果我们移动文件的时候使用了StandardCopyOption.ATOMIC_MOVE选项,其他所有选项就都会被忽略,并且如果目标文件已经存在,老文件既不会被替换也不会有IOException异常抛出,结果和具体的系统实现有关。如果移动文件不能被原子性的完成,AtomicMoveNotSupportedException异常会被抛出。
删除文件可以使用Files的delete和deleteIfExists这两个方法。顾名思义,当文件不存在时deleteIfExists的删除结果为false。如果要删除一个文件夹,文件夹必须是空的,或者结合使用SimpleFileVisitor来将文件夹下所有内容都删除。
至此我们可以看到,Java7中复制删除或移动文件还是比较简单的,避免了之前过于复杂的API,而且大部分功能都是通过Files的静态方法实现的,对于我们使用非常方便。但文件的操作涉及到具体不同的操作系统是对文件的管理方式,因此我们还要对操作系统有一定的了解并正确使用不同的操作参数,才能更好的运用Java7中提供的这些API。
首先来说如何创建一个新的文件夹和文件,直接上例子。
public static void main(String[] args) { try { Path directoryPath = Paths.get("D:/home/sample"); Files.createDirectory(directoryPath); System.out.println("Directory created successfully!"); Path filePath = Paths.get("D:/home/sample/test.txt"); Files.createFile(filePath); System.out.println("File created successfully!"); Path directoriesPath = Paths.get("D:/home/sample/subtest/subsubtest"); System.out.println("Sub-directory created successfully!"); Files.createDirectories(directoriesPath); } catch (FileAlreadyExistsException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
上例中,在调用createFile方法时,如果想要创建的文件已经存在,FileAlreadyExistsException会被抛出。createFile和createDirectory这个两个方法都是原子性的,即要不整个操作都能成功或者整个操作都失败。
复制一个文件同样非常简单,Files的copy方法就可以实现。在复制文件时,我们可以对复制操作加一个参数来指明具体如何进行复制。java.lang.enum.StandardCopyOption这个枚举可以用作参数传递给copy方法。
ATOMIC_MOVE | 原子性的复制 |
COPY_ATTRIBUTES | 将源文件的文件属性信息复制到目标文件中 |
REPLACE_EXISTING | 替换已存在的文件 |
public static void main(String[] args) { Path newFile = Paths.get("D:/home/sample/newFile.txt"); Path copiedFile = Paths.get("D:/home/sample/copiedFile.txt"); try { Files.createFile(newFile); System.out.println("File created successfully!"); Files.copy(newFile, copiedFile, StandardCopyOption.REPLACE_EXISTING); System.out.println("File copied successfully!"); } catch (IOException e) { e.printStackTrace(); } }
此外copy方法还支持输入输出流作为参数,以来复制非文件系统的信息。而复制文件夹的操作也并不复杂,如下例。
public static void main(String[] args) { Path originalDirectory = Paths.get("D:/home/sample"); Path newDirectory = Paths.get("D:/home/sample/tmp"); try { Files.copy(originalDirectory, newDirectory); System.out.println("Directory copied successfully!"); } catch (IOException e) { e.printStackTrace(); } }
public static void main(String[] args) { Path newFile = Paths.get("D:/home/sample/java7WebSite.html"); URI url = URI.create("http://jdk7.java.net/"); try (InputStream inputStream = url.toURL().openStream()) { Files.copy(inputStream, newFile); System.out.println("Site copied successfully!"); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
在我们做开发工作的时候,有时需要用到一个临时文件做介质,这些临时文件不需要被持久的保存下来,当程序结束或者一个方法处理完,就可以被删除掉了。Java7中提供了对临时文件良好的操作方法。
public static void main(String[] args) { try { Path rootDirectory = Paths.get("D:/home/sample"); Path tempDirectory = Files.createTempDirectory(rootDirectory, ""); System.out.println("Temporary directory created successfully!"); String dirPath = tempDirectory.toString(); System.out.println(dirPath); Path tempFile = Files.createTempFile(tempDirectory, "", ""); System.out.println("Temporary file created successfully!"); String filePath = tempFile.toString(); System.out.println(filePath); } catch (IOException e) { e.printStackTrace(); } }
我们可以通过给createTempDirectory和createTempFile方法传递不同的参数来指定临时文件的前缀和后缀,具体使用方式请参照JDK文档。
Files类还提供了一些方法,方便我们修改那些文件本身和时间相关的属性。
public static void main(String[] args) { try { Path path = Paths.get("D:/home/projects/note.txt"); BasicFileAttributeView view = Files.getFileAttributeView(path, BasicFileAttributeView.class); FileTime lastModifiedTime; FileTime lastAccessTime; FileTime createTime; BasicFileAttributes attributes = view.readAttributes(); lastModifiedTime = attributes.lastModifiedTime(); createTime = attributes.creationTime(); long currentTime = Calendar.getInstance().getTimeInMillis(); lastAccessTime = FileTime.fromMillis(currentTime); view.setTimes(lastModifiedTime, lastAccessTime, createTime); System.out.println(attributes.lastAccessTime()); Files.setLastModifiedTime(path, lastModifiedTime); System.out.println(Files.getLastModifiedTime(path)); } catch (IOException e) { e.printStackTrace(); } }
当要修改文件所属用户的时候,运行Java程序的用户需要有特定的权限,这里对不同操作系统的权限控制方式不做介绍,大家可以自己学习一下。下例中的用户JavaUser必须是存在在系统中的,否则会抛UserPrincipalNotFoundException异常。
public static void main(String[] args) { try { Path path = Paths.get("D:/home/projects/note.txt"); UserPrincipalLookupService lookupService = FileSystems.getDefault().getUserPrincipalLookupService(); UserPrincipal userPrincipal = lookupService.lookupPrincipalByName("JavaUser"); Files.setOwner(path, userPrincipal); System.out.println("Owner: " + Files.getOwner(path)); } catch (IOException e) { e.printStackTrace(); } }
移动文件有一些地方需要注意,首先是如果移动一个文件夹,文件夹和其子文件夹都会被移动,跨磁盘移动的文件夹时,目标文件夹必须是空的,否则会有DirectoryNotEmptyException异常抛出。
如果我们移动文件的时候使用了StandardCopyOption.ATOMIC_MOVE选项,其他所有选项就都会被忽略,并且如果目标文件已经存在,老文件既不会被替换也不会有IOException异常抛出,结果和具体的系统实现有关。如果移动文件不能被原子性的完成,AtomicMoveNotSupportedException异常会被抛出。
public static void main(String[] args) { try { Path sourceFile = Paths.get("D:/home/projects/note.txt"); Path destinationFile = Paths.get("D:/home/sample/note.txt"); Files.move(sourceFile, destinationFile, StandardCopyOption.REPLACE_EXISTING); System.out.println("File moved successfully!"); } catch (IOException e) { e.printStackTrace(); } }
删除文件可以使用Files的delete和deleteIfExists这两个方法。顾名思义,当文件不存在时deleteIfExists的删除结果为false。如果要删除一个文件夹,文件夹必须是空的,或者结合使用SimpleFileVisitor来将文件夹下所有内容都删除。
public static void main(String[] args) { try { Path sourceFile = Paths.get("D:/home/projects/note_bak1.txt"); boolean result = Files.deleteIfExists(sourceFile); if (result) { System.out.println("File deleted successfully!"); } sourceFile = Paths.get("D:/home/projects/note_bak2.txt"); Files.delete(sourceFile); System.out.println("File deleted successfully!"); } catch (NoSuchFileException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
至此我们可以看到,Java7中复制删除或移动文件还是比较简单的,避免了之前过于复杂的API,而且大部分功能都是通过Files的静态方法实现的,对于我们使用非常方便。但文件的操作涉及到具体不同的操作系统是对文件的管理方式,因此我们还要对操作系统有一定的了解并正确使用不同的操作参数,才能更好的运用Java7中提供的这些API。