Introduction to the Java NIO2 File API

GitHub

NIO2中的文件API是Java 7附带的Java平台的主要新功能之一,特别是新的文件系统API的一个子集以及Path APIs。

在用户的主目录(home directory)下操作,使得对于所有的操作系统都是有效的。[内部是如何实现的呢???]

private static String HOME = System.getProperty("user.home");

Files类是Java.nio.file包的一个主要入口。这个类提供了丰富的APIs来读,写,操纵文件和目录。Files类方法在Path对象的实例上起作用。

1.检查一个文件或目录

我们可以让一个Path实例表示文件系统中的一个文件或目录。它所指向的那个文件或目录是否存在,是否可访问,可以通过文件操作来确认。

每当我们使用术语File时,除非另有说明,否则我们将指代File和目录。

检查一个File是否存在,使用exists

@Test
public void givenExistentPath_whenConfirmsFileExists_thenCorrect() {
Path p = Paths.get(HOME); assertTrue(Files.exists(p));
}

检查一个File不存在,使用notExists

@Test
public void givenNonexistentPath_whenConfirmsFileNotExists_thenCorrect() {
Path p = Paths.get(HOME + "/inexistent_file.txt"); assertTrue(Files.notExists(p));
}

检查一个File是标准文件,像myfile.txt,还是只是个目录,使用isRegularFile :

@Test
public void givenDirPath_whenConfirmsNotRegularFile_thenCorrect() {
Path p = Paths.get(HOME); assertFalse(Files.isRegularFile(p));
}

可以检查文件的权限。检查一个文件是否可读,使用isReadable :

@Test
public void givenExistentDirPath_whenConfirmsReadable_thenCorrect() {
Path p = Paths.get(HOME); assertTrue(Files.isReadable(p));
}

检查一个文件是否可写,使用isWritable :

@Test
public void givenExistentDirPath_whenConfirmsWritable_thenCorrect() {
Path p = Paths.get(HOME); assertTrue(Files.isWritable(p));
}

检查一个文件是否可执行,使用isExecutable :

@Test
public void givenExistentDirPath_whenConfirmsExecutable_thenCorrect() {
Path p = Paths.get(HOME);
assertTrue(Files.isExecutable(p));
}

有两个paths,可以检查它们在底层文件系统上是否指向相同的文件。

@Test
public void givenSameFilePaths_whenConfirmsIsSame_thenCorrect() {
Path p1 = Paths.get(HOME);
Path p2 = Paths.get(HOME); assertTrue(Files.isSameFile(p1, p2));
}

2.创建Files

文件系统API提供了用于创建文件的单行操作。要创建一个标准文件,使用createFile,传给它代表我们要创建的文件的path对象。

在path中的所有名字元素(name elements)除了文件名外必须存在。否则会得到一个IOException。

@Test
public void givenFilePath_whenCreatesNewFile_thenCorrect() {
String fileName = "myfile_" + UUID.randomUUID().toString() + ".txt";
Path p = Paths.get(HOME + "/" + fileName);
assertFalse(Files.exists(p)); Files.createFile(p); assertTrue(Files.exists(p));
}

要创建目录,使用createDirectory :

@Test
public void givenDirPath_whenCreatesNewDir_thenCorrect() {
String dirName = "myDir_" + UUID.randomUUID().toString();
Path p = Paths.get(HOME + "/" + dirName);
assertFalse(Files.exists(p)); Files.createDirectory(p); assertTrue(Files.exists(p));
assertFalse(Files.isRegularFile(p));
assertTrue(Files.isDirectory(p));
}

这个操作也要求path中的所有名字元素都存在。如果不是的话,也会得到IOException

@Test(expected = NoSuchFileException.class)
public void givenDirPath_whenFailsToCreateRecursively_thenCorrect() {
String dirName = "myDir_" + UUID.randomUUID().toString() + "/subdir";
Path p = Paths.get(HOME + "/" + dirName);
assertFalse(Files.exists(p)); Files.createDirectory(p);
}

如果想仅一次调用就创建一个层次的目录结构,使用createDirectories。和之前的操作不一样,当它在path中遇到丢失的名字元素时,它不会抛出IOException,它会递归创建它们直到最后一个元素:

@Test
public void givenDirPath_whenCreatesRecursively_thenCorrect() {
Path dir = Paths.get(
HOME + "/myDir_" + UUID.randomUUID().toString());
Path subdir = dir.resolve("subdir");
assertFalse(Files.exists(dir));
assertFalse(Files.exists(subdir)); Files.createDirectories(subdir); assertTrue(Files.exists(dir));
assertTrue(Files.exists(subdir));
}

3.创建临时Files

许多应用在它们运行时会在文件系统中创建临时文件的踪迹。结果大部分文件系统有一个专用目录来存储这样的应用产生的临时文件。

新的文件系统API为这个目的提供了特定的操作。createTempFile API就执行这个操作。它要传入的参数时一个path对象,一个文件前缀,一个文件后缀。

@Test
public void givenFilePath_whenCreatesTempFile_thenCorrect() {
String prefix = "log_";
String suffix = ".txt";
Path p = Paths.get(HOME + "/"); Files.createTempFile(p, prefix, suffix); assertTrue(Files.exists(p));
}

这些参数对于创建临时文件的需求是足够了的。但是,如果要指定文件特定的属性,还有第四个可变参数的参数。

上面的测试在HOME目录创建了一个临时文件,分别插入和追加了提供的前后缀字符串。将会得到文件如:log_8821081429012075286.txt。

这个长的数字串是系统生成的。

然而,如果不提供前后缀,文件名就只包含长数字串和默认的.tmp扩展名。

@Test
public void givenPath_whenCreatesTempFileWithDefaults_thenCorrect() {
Path p = Paths.get(HOME + "/"); Files.createTempFile(p, null, null); assertTrue(Files.exists(p));
}

生成的文件像:8600179353689423985.tmp

如果path,前缀,后缀都不提供,这个操作将使用默认的输出。被创建文件的默认位置就是文件系统提供的临时文件目录:

@Test
public void givenNoFilePath_whenCreatesTempFileInTempDir_thenCorrect() {
Path p = Files.createTempFile(null, null); assertTrue(Files.exists(p));
}

Windows中,默认就像:C:\Users\user\AppData\Local\Temp\6100927974988978748.tmp.

通过使用createTempDirectory而不是createTempFile,上面所有的操作可用于创建目录而不是标准文件。

4.删除File

为了删除一个文件,使用delete API。为了清晰起见,下面的测试首先确保文件已经不存在,然后创建它并且确认现在它存在了,最后删掉它并确认它不再存在了。

@Test
public void givenPath_whenDeletes_thenCorrect() {
Path p = Paths.get(HOME + "/fileToDelete.txt");
assertFalse(Files.exists(p));
Files.createFile(p);
assertTrue(Files.exists(p)); Files.delete(p); assertFalse(Files.exists(p));
}

如果文件不存在文件系统中,delete操作抛出IOException。

@Test(expected = NoSuchFileException.class)
public void givenInexistentFile_whenDeleteFails_thenCorrect() {
Path p = Paths.get(HOME + "/inexistentFile.txt");
assertFalse(Files.exists(p)); Files.delete(p);
}

使用deleteIfExists可以避免这个场景,如果文件不存在它会默默地失败。当多个线程执行这个操作并且我们不想要失败信息时很有用。因为一个线程比当前失败的线程更早执行操作。[???]

@Test
public void givenInexistentFile_whenDeleteIfExistsWorks_thenCorrect() {
Path p = Paths.get(HOME + "/inexistentFile.txt");
assertFalse(Files.exists(p)); Files.deleteIfExists(p);
}

处理目录而不是标准文件时,要记住,delete操作默认不会递归操作。如果目录不是空的,就会失败抛出IOException。

@Test(expected = DirectoryNotEmptyException.class)
public void givenPath_whenFailsToDeleteNonEmptyDir_thenCorrect() {
Path dir = Paths.get(
HOME + "/emptyDir" + UUID.randomUUID().toString());
Files.createDirectory(dir);
assertTrue(Files.exists(dir)); Path file = dir.resolve("file.txt");
Files.createFile(file); Files.delete(dir); assertTrue(Files.exists(dir));
}

5.复制Files

使用copy API复制一个文件或目录:

@Test
public void givenFilePath_whenCopiesToNewLocation_thenCorrect() {
Path dir1 = Paths.get(
HOME + "/firstdir_" + UUID.randomUUID().toString());
Path dir2 = Paths.get(
HOME + "/otherdir_" + UUID.randomUUID().toString()); Files.createDirectory(dir1);
Files.createDirectory(dir2); Path file1 = dir1.resolve("filetocopy.txt");
Path file2 = dir2.resolve("filetocopy.txt"); Files.createFile(file1); assertTrue(Files.exists(file1));
assertFalse(Files.exists(file2)); Files.copy(file1, file2); assertTrue(Files.exists(file2));
}

目标文件存在的话,复制就失败。除非指定了REPLACE_EXISTING。

@Test(expected = FileAlreadyExistsException.class)
public void givenPath_whenCopyFailsDueToExistingFile_thenCorrect() {
Path dir1 = Paths.get(
HOME + "/firstdir_" + UUID.randomUUID().toString());
Path dir2 = Paths.get(
HOME + "/otherdir_" + UUID.randomUUID().toString()); Files.createDirectory(dir1);
Files.createDirectory(dir2); Path file1 = dir1.resolve("filetocopy.txt");
Path file2 = dir2.resolve("filetocopy.txt"); Files.createFile(file1);
Files.createFile(file2); assertTrue(Files.exists(file1));
assertTrue(Files.exists(file2)); Files.copy(file1, file2); Files.copy(file1, file2, StandardCopyOption.REPLACE_EXISTING);
}

复制目录时,内容是不会递归地复制的。

比如:/baeldung包含/articles.db/authors.db文件复制/baeldung 到新位置将会创建一个空的目录。

6.移动Files

使用move API移动文件或目录。它在很大程度上与复制操作相似。如果复制操作类似于基于GUI的系统中的复制和粘贴操作,则移动类似于剪切和粘贴操作:

@Test
public void givenFilePath_whenMovesToNewLocation_thenCorrect() {
Path dir1 = Paths.get(
HOME + "/firstdir_" + UUID.randomUUID().toString());
Path dir2 = Paths.get(
HOME + "/otherdir_" + UUID.randomUUID().toString()); Files.createDirectory(dir1);
Files.createDirectory(dir2); Path file1 = dir1.resolve("filetocopy.txt");
Path file2 = dir2.resolve("filetocopy.txt");
Files.createFile(file1); assertTrue(Files.exists(file1));
assertFalse(Files.exists(file2)); Files.move(file1, file2); assertTrue(Files.exists(file2));
assertFalse(Files.exists(file1));
}

如果目标文件存在,移动操作将失败,除非REPLACE_EXISTING选项被指定了,就像我们对复制操作所做的一样:

@Test(expected = FileAlreadyExistsException.class)
public void givenFilePath_whenMoveFailsDueToExistingFile_thenCorrect() {
Path dir1 = Paths.get(
HOME + "/firstdir_" + UUID.randomUUID().toString());
Path dir2 = Paths.get(
HOME + "/otherdir_" + UUID.randomUUID().toString()); Files.createDirectory(dir1);
Files.createDirectory(dir2); Path file1 = dir1.resolve("filetocopy.txt");
Path file2 = dir2.resolve("filetocopy.txt"); Files.createFile(file1);
Files.createFile(file2); assertTrue(Files.exists(file1));
assertTrue(Files.exists(file2)); Files.move(file1, file2); Files.move(file1, file2, StandardCopyOption.REPLACE_EXISTING); assertTrue(Files.exists(file2));
assertFalse(Files.exists(file1));
}

Java NIO2 File API介绍的更多相关文章

  1. java===字符串常用API介绍(转)

    本文转自:http://blog.csdn.net/crazy_kid_hnf/article/details/55102861 字符串基本操作 1.substring(from,end)(含头不含尾 ...

  2. JAVA File常用的API介绍

    package coreJava; import java.io.File; import java.io.IOException; public class FileDemo { public st ...

  3. PhoneGap API介绍:File

    本文将介绍PhoneGap API——File:通过JavaScript截获本地文件系统.File是用于读取.写入和浏览文件系统层次结构的PhoneGap API. 对象: DirectoryEntr ...

  4. Java中File类的使用介绍

    1.创建File对象的几种方式 import java.io.File; public class MyFile { public static void main(String[] args) { ...

  5. Java阻塞队列四组API介绍

    Java阻塞队列四组API介绍 通过前面几篇文章的学习,我们已经知道了Java中的队列分为阻塞队列和非阻塞队列以及常用的七个阻塞队列.如下图: 本文来源:凯哥Java(kaigejava)讲解Java ...

  6. 微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍

    微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍 上一篇关于网关的文章: 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Ngi ...

  7. HTML5 File API 全介绍

    在 HTML5 File API 出现之前,前端对于文件的操作是非常有局限性的,大多需要配合后端实现.出于安全角度考虑,从本地上传文件时,代码不可能获取文件在用户本地的地址,所以纯前端不可能完成一些类 ...

  8. 使用 JavaScript File API 实现文件上传

    概述 以往对于基于浏览器的应用而言,访问本地文件都是一件头疼的事情.虽然伴随着 Web 2.0 应用技术的不断发展,JavaScript 正在扮演越来越重要的角色,但是出于安全性的考虑,JavaScr ...

  9. Java笔记--File,FileInputStream,FileReader,InputStreamReader,BufferedReader 的使用和区别

    转自:http://hi.baidu.com/danghj/item/0ef2e2c4ab95af7489ad9e39 参考资料:  < core java > 12 章 使用 Java ...

随机推荐

  1. Qt之模式、非模式对话框

    关于“模式”和“非模式”对话框,相信大家都比较熟悉,但其中有一个可能很多人都比较陌生,介于两者之间的状态,我们称之为“半模式“. 模式对话框 描述 阻塞同一应用程序中其它可视窗口输入的对话框.模式对话 ...

  2. elasticsearch插件三—— Marvel插件安装详解

    2016年05月21日 22:58:13 阅读数:23058 一.Marvel插件介绍 Marvel插件:在簇中从每个节点汇集数据.这个插件必须每个节点都得安装. Marvel是Elasticsear ...

  3. 解决微信小程序中Date.parse()获取时间戳IOS不兼容的问题(IOS为NaN的问题)

    前端同事在做微信小程序时发现IOS获取的时间戳为空的问题,后来通过跟踪发现,原来是因为IOS系统不支持2017-01-01格式的时间导致的, var mydata = '2017-01-01 11:0 ...

  4. 同学帮帮 h5 刮刮卡组件:Txbb.Scratch

    同学帮帮 h5 刮刮卡组件,简洁.无依赖,支持 globals 和 amd 两种调用方式. 暂时只能用在移动端 使用方法 <div id="J-Scratch">< ...

  5. Linux上创建SSH隧道

    Win上有好用的Xshell,可以做SSH隧道,但是Linux没有很好用的工具,本来gSTM还可以,但是死活装不上,也很久没更新了. 但其实,Linux上直接使用ssh命令就可以创建SSH隧道,非常方 ...

  6. vmware复制虚拟机出现Error:No suitable device found:no device found for connection 'System eth0'

    vmware复制虚拟机出现Error:No suitable device found:no device found for connection 'System eth0' 废话不多说,直接给出解 ...

  7. C++ 类模板三(类模版中的static关键字)

    //类模版中的static关键字 #include<iostream> using namespace std; /* 类模板本质上是c++编译器根据类型参数创建了不同的类, c++编译器 ...

  8. Python之Matplotlib库常用函数大全(含注释)

    plt.savefig(‘test’, dpi = 600) :将绘制的图画保存成png格式,命名为 test plt.ylabel(‘Grade’) :  y轴的名称 plt.axis([-1, 1 ...

  9. 假设web应用的文档根目录为MyApp,那么可以从哪里找到database.jar文件。

    假设web应用的文档根目录为MyApp,那么可以从哪里找到database.jar文件. A. MyApp目录下 B. MyApp\images目录下 C. MyApp\WEB-INF目录下 D. M ...

  10. C++学习之拷贝构造函数篇

    一.拷贝构造函数的声明 Array(const Array & arr); 二.拷贝构造函数的实现分为两种,即是深拷贝和浅拷贝. 1.浅拷贝 代码例如以下: class Array { pub ...