在先前的文章中,我讨论了文件和目录的创建( 创建文件和目录 )以及选择( 列出和过滤目录内容 )。 采取的最后一个合乎逻辑的步骤是探索我们如何使用它们以及如何使用它们。 这是库的一部分,它经过了重新设计。 这方面的更新包括保证某些操作的原子性,API改进,性能优化以及引入适当的异常层次结构,这些层次结构取代了IO库以前版本中的boolean返回方法。

开启档案

在开始阅读和写入文件之前,我们需要介绍这些操作的一个共同基础-文件的打开方式。 文件的打开方式直接影响这些操作的结果及其性能。 让我们看一下打开枚举java.nio.file.StandardOpenOption包含的文件的标准选项:

标准打开选项
描述
APPEND 如果打开该文件以进行WRITE访问,则字节将被写入文件的末尾而不是开头。
CREATE 如果不存在,请创建一个新文件。
CREATE_NEW 创建一个新文件,如果文件已经存在则失败。
DELETE_ON_CLOSE 关闭删除。
DSYNC 要求对文件内容的每次更新都同步写入基础存储设备。
READ 打开以进行读取访问。
SPARSE 稀疏文件。
SYNC 要求对文件内容或元数据的每次更新都同步写入基础存储设备。
TRUNCATE_EXISTING 如果该文件已经存在并且已打开以进行WRITE访问,则其长度将被截断为0。
WRITE 打开以进行写访问。

这些都是开发人员您可能需要正确处理文件打开(无论是读取还是写入)的所有标准选项。

读取文件

在读取文件时,NIO.2提供了几种方法来实现–每种方法都有其优缺点。 这些方法如下:

  • 将文件读入字节数组
  • 使用无缓冲流
  • 使用缓冲流

让我们来看看第一个选项。 类Files提供了方法readAllBytes来做到这一点。 将文件读入字节数组似乎很简单,但这可能仅适用于非常有限的文件范围。 由于我们将整个文件放入内存中,因此必须注意该文件的大小。 仅当我们尝试读取小文件时,使用此方法才是合理的,并且可以立即完成。 如以下代码段所示,这是非常简单的操作:

Path filePath = Paths.get("C:", "a.txt");if (Files.exists(filePath)) {try {byte[] bytes = Files.readAllBytes(filePath);String text = new String(bytes, StandardCharsets.UTF_8);System.out.println(text);} catch (IOException e) {throw new RuntimeException(e);}
}

上面的代码首先将文件读取到字节数组中,然后使用以下输出构造包含该文件内容的字符串对象:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet justo nec leo euismod porttitor. Vestibulum id sagittis nulla, eu posuere sem. Cras commodo, massa sed semper elementum, ligula orci malesuada tortor, sed iaculis ligula ligula et ipsum.

当我们需要以字符串形式读取文件的内容时,可以使用上面的代码。 但是,这种解决方案不是很干净,我们可以使用类Files readAllLines来避免这种尴尬的构造。 当需要逐行读取人类可读的输出时,此方法可作为读取文件的便捷解决方案。 此方法的使用再次非常简单,并且与前面的示例非常相似(有相同的限制):

Path filePath = Paths.get("C:", "b.txt");if (Files.exists(filePath)) {try {List<String> lines = Files.readAllLines(filePath, StandardCharsets.UTF_8);for (String line : lines) {System.out.println(line);}} catch (IOException e) {throw new RuntimeException(e);}
}

具有以下输出:

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam sit amet justo nec leo euismod porttitor.
Vestibulum id sagittis nulla, eu posuere sem.
Cras commodo, massa sed semper elementum, ligula orci malesuada tortor, sed iaculis ligula ligula et ipsum.

使用流读取文件

继续使用更复杂的方法,我们总是可以使用良好的旧流,就像我们以前使用该库的以前版本一样。 既然这是众所周知的基础,我将仅展示如何获取这些流的实例。 首先,我们可以通过调用newInputStream方法从类Files检索InputStream实例。 像往常一样,可以进一步使用装饰器模式,并从中输出缓冲流。 为了方便起见,使用方法newBufferedReader 。 这两个方法都返回一个流实例,该实例是普通的旧java.io对象。

Path filePath1 = Paths.get("C:", "a.txt");
Path filePath2 = Paths.get("C:", "b.txt");InputStream is = Files.newInputStream(filePath1);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);BufferedReader reader = Files.newBufferedReader(filePath2, StandardCharsets.UTF_8);

写入文件

写入文件与NIO.2库提供的一系列工具中的读取过程相似,因此只需回顾一下:

  • 将字节数组写入文件
  • 使用无缓冲流
  • 使用缓冲流

再次让我们首先探索字节数组选项。 毫不奇怪,类Files支持我们方法write两个变体。 我们正在从数组或文本行中写入字节,我们在这里需要关注StandardOpenOptions ,因为这两种方法都可能受到这些修饰符的自定义选择的影响。 默认情况下,如果没有将StandardOpenOption传递给该方法,则write方法的行为就像存在CREATETRUNCATE_EXISTINGWRITE选项一样(如Javadoc中所述)。 话虽如此,请注意不要使用默认(无打开选项)版本的write方法,因为它要么创建一个新文件,要么最初将现有文件截断为零大小。 写入完成后,文件会自动关闭-成功写入后会引发异常。 对于文件大小,适用与readAllBytes相同的限制。

下面的示例演示如何将字节数组写入文件。 请注意,由于write方法的默认行为,因此没有任何检查方法。 该示例可以多次运行,并具有两个不同的结果。 第一次运行将创建一个文件,将其打开以进行写入,然后将数组bytes写入此文件。 此代码的任何后续调用都将擦除该文件,并将bytes数组的内容写入此空文件。 两次运行都将导致文本为“ Hello world!”的封闭文件。 写在第一行。

Path newFilePath = Paths.get("/home/jstas/a.txt");
byte[] bytes = new byte[] {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21};try {Files.write(newFilePath, bytes);
} catch(IOException e) {throw new RuntimeException(e);
}

当我们需要写行而不是字节时,我们可以将字符串转换为字节数组,但是,还有一种更方便的方法。 只需准备一行列表,然后将其传递给write方法即可。 请注意以下示例中两个StandardOpenOption的使用。 通过使用这些选项,我可以确保存在一个文件(如果不存在,则会创建该文件)以及将数据追加到该文件的方式(因此不会丢失任何先前写入的数据)。 整个例子很简单,看一下:

Path filePath = Paths.get("/home/jstas/b.txt");List<String> lines = new ArrayList<>();
lines.add("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
lines.add("Aliquam sit amet justo nec leo euismod porttitor.");
lines.add("Vestibulum id sagittis nulla, eu posuere sem.");
lines.add("Cras commodo, massa sed semper elementum, ligula orci malesuada tortor, sed iaculis ligula ligula et ipsum.");try {Files.write(filePath, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
} catch (IOException e) {throw new RuntimeException(e);
}

使用流写入文件

对于较大的文件,使用字节数组可能不是一个好主意。 这是流进入的时间。类似于阅读本章,我将不解释流或如何使用它们。 我宁愿专注于一种检索其实例的方法。 类Files提供了newOutputStream方法,该方法接受StandardOpenOption来自定义流行为。 默认情况下,当没有将StandardOpenOption传递给该方法时,流write方法的行为就像存在CREATETRUNCATE_EXISTINGWRITE选项一样(如Javadoc中所述)。 该流没有被缓冲,但是通过一点装饰器魔术,您可以创建BufferedWriter实例。 为了解决这种不便,NIO.2附带了newBufferWriter方法,该方法可立即创建缓冲的流实例。 以下代码段显示了两种方式:

Path filePath1 = Paths.get("/home/jstas/c.txt");
Path filePath2 = Paths.get("/home/jstas/d.txt");OutputStream os = Files.newOutputStream(filePath1);
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);BufferedWriter writer = Files.newBufferedWriter(filePath2, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND);

复制和移动文件和目录

复制文件和目录

NIO.2最受欢迎的功能之一是处理复制和移动文件和目录的更新方式。 为了使所有内容保持一致,设计人员决定在新文件系统API中引入两个父(标记)接口: OpenOptionCopyOption (这两个接口均来自包java.nio.file )。 上一章提到的StandardOpenOption枚举实现了OpenOption接口。 CopyOption接口具有两个实现,其中一个已经在关于NIO.2中的Links的帖子中见过。 你们中有些人可能还记得LinkOption枚举,它被称为实现指导方法来处理链接相关的操作。 但是,还有另一种实现–包java.nio.file StandardCopyOption枚举。 再次,我们将看到另一个枚举–用于指导复制操作。 因此,在深入研究任何代码之前,让我们回顾一下使用不同的复制选项可以实现的目标。

标准复印选项
描述
ATOMIC_MOVE 将文件作为原子文件系统操作移动。
COPY_ATTRIBUTES 将属性复制到新文件。
REPLACE_EXISTING 替换现有文件(如果存在)。

使用这些选项来指导您的IO操作非常简单,也很简单。 由于我们正在尝试复制文件,因此ATOMIC_MOVE使用意义不大(您仍然可以使用它,但最终会出现java.lang.UnsupportedOperationException: Unsupported copy option )。 类Files提供了三种copy方法,可用于不同目的:

  • copy(InputStream in, Path target, CopyOption... options)

    • 将所有字节从输入流复制到文件。
  • copy(Path source, OutputStream out)
    • 将所有字节从文件复制到输出流。
  • copy(Path source, Path target, CopyOption... options)
    • 将文件复制到目标文件。

在我们获得任何代码之前,我相信最好了解copy方法的最重要的行为功能(上述三个方法中的最后一个)。 copy方法的行为如下(基于Javadoc):

  • 默认情况下,如果目标文件已经存在或为符号链接,则复制失败。
  • 如果源和目标是同一文件,则该方法将完成而无需复制该文件。 (有关更多信息,请查看类Files方法isSameFile
  • 不需要将文件属性复制到目标文件。
  • 如果源文件是目录,则它将在目标位置创建一个空目录(不复制目录中的条目)。
  • 复制文件不是原子操作。
  • 自定义实现可能会带来新的特定选项。

这些是copy方法内部工作的核心原理。 现在是查看代码示例的好时机。 由于此方法非常易于使用,因此可以将其实际使用(使用最常见的copy方法形式)。 如预期的那样,以下代码将复制源文件(并可能覆盖目标文件)并保留文件属性:

Path source = Paths.get("/home/jstas/a.txt");
Path target = Paths.get("/home/jstas/A/a.txt");try {Files.copy(source, target, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {throw new RuntimeException(e);
}

这里没有什么大的惊喜–代码复制带有文件属性的源文件。 如果您觉得我忘记了(不是空的)目录,请让我向我保证。 也可以使用NIO.2复制,移动或删除填充的目录,但这是我将在下一篇文章中介绍的内容,因此您将不得不等待几天。

移动文件和目录

在移动文件时,我们再次需要能够指定选项,以指导方法从Filesmove的过程。 在这里,我们利用了上一章中提到的StandardCopyOptions 。 两个相关选项是ATOMIC_MOVEREPLACE_EXISTING 。 首先,让我们从一些基本特征入手,然后继续进行代码示例:

  • 默认情况下,如果目标文件已存在,则move方法将失败。
  • 如果源文件和目标文件是同一文件,则该方法将完成而不移动文件。 (有关更多信息,请查看类Files方法isSameFile
  • 如果源是符号链接,则链接本身将被移动。
  • 如果源文件是目录,则必须为空才能移动。
  • 不需要移动文件属性。
  • 可以将移动文件配置为原子操作,但不必这样做。
  • 自定义实现可能会带来新的特定选项。

代码非常简单,因此让我们看下面的代码片段:

Path source = Paths.get("/home/jstas/b.txt");
Path target = Paths.get("/home/jstas/A/b.txt");try {Files.move(source, target, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
} catch(IOException e) {throw new RuntimeException(e);
}

如预期的那样,代码以原子操作移动源文件。

删除文件和目录

本文的最后一部分致力于删除文件和目录。 再次删除文件非常简单,可以使用两种可能的方法来调用(通常都从Files类):

  • public static void delete(Path path)
  • public static boolean deleteIfExists(Path path)

两种方法使用相同的规则:

  • 默认情况下,当文件是目录并且不为空时,删除方法将失败,并出现DirectoryNotEmptyException
  • 如果文件是符号链接,则链接本身将被删除。
  • 删除文件可能不是原子操作。
  • 如果文件已打开或被JVM或其他软件使用,则可能不会删除文件。
  • 自定义实现可能会带来新的特定选项。
Path newFile = Paths.get("/home/jstas/c.txt");
Path nonExistingFile = Paths.get("/home/jstas/d.txt");try {Files.createFile(newFile);Files.delete(newFile);System.out.println("Any file deleted: " + Files.deleteIfExists(nonExistingFile));
} catch(IOException e) {throw new RuntimeException(e);
}

输出:

Any file deleted: false

翻译自: https://www.javacodegeeks.com/2014/06/working-with-files-and-directories-in-nio-2.html

在NIO.2中使用文件和目录相关推荐

  1. nio 读取目录所有文件_在NIO.2中使用文件和目录

    nio 读取目录所有文件 在先前的文章中,我讨论了文件和目录的创建( 创建文件和目录 )以及选择( 列出和过滤目录内容 ). 采取的最后一个合乎逻辑的步骤是探索我们如何使用它们以及如何使用它们. 这是 ...

  2. 在NIO.2中创建文件和目录

    如今,大量的应用程序创建文件或目录的目的非常广泛. 无论是生成报告,导出配置文件还是仅存储一些数据,能够处理这些任务都非常重要. 创建文件和目录是使用文件系统时最常用的功能之一. 图书馆的这一部分进行 ...

  3. object-c中管理文件和目录:NSFileManager使用方法

    object-c中管理文件和目录:NSFileManager使用方法 对于NSFileManager,文件或目录是使用文件的路径名唯一标识的.每一个路径名都是一个NSString对象,它可以是相对路径 ...

  4. python操作目录_详解python中的文件与目录操作

    详解python中的文件与目录操作 一 获得当前路径 1.代码1 >>>import os >>>print('Current directory is ',os. ...

  5. python显示目录中的文件_Python中的文件和目录操作实现

    Python中的文件和目录操作实现 对于文件和目录的处理,虽然可以通过操作系统命令来完成,但是Python语言为了便于开发人员以编程的方式处理相关工作,提供了许多处理文件和目录的内置函数.重要的是,这 ...

  6. junit rule_使用@Rule在JUnit中测试文件和目录

    junit rule 多亏了TemporaryFolder @Rule在JUnit中使用文件和目录进行测试很容易. 在JUnit中,规则( @Rule )可以用作夹具设置和清除方法( org.juni ...

  7. 使用@Rule在JUnit中测试文件和目录

    多亏了TemporaryFolder @Rule在JUnit中使用文件和目录进行测试很容易. 在JUnit中,规则( @Rule )可以替代或设置夹具设置和清除方法( org.junit.Before ...

  8. PHP笔记-通过输入获取文件夹中的文件和目录例子

    程序运行截图如下: 点击提交后打印此内容: 文件结构如下: 源码如下: dirFile.php <?phpfunction dirFile($dir, &$error){if(!is_d ...

  9. linux防止文件被复制,技术|如何在 Linux 系统中防止文件和目录被意外的删除或修改...

    有时,我会不小心的按下 SHIFT+DELETE来删除我的文件数据.是的,我是个笨蛋,没有再次确认下我实际准备要删除的东西.而且我太笨或者说太懒,没有备份我的文件数据.结果呢?数据丢失了!在一瞬间就丢 ...

最新文章

  1. python怎么写文件-来看文件处理Python怎么写?
  2. 持续高温引发百姓热议 ***趁机放毒谋取暴利
  3. 北京工商大学计算机学院研究生院,北京工商大学计算机学院
  4. 《啊哈!算法》笔记_Day01
  5. 3DSlicer30:VS-Qt5VSaddin-qt4.8.7dev
  6. apache重写规则转Nginx
  7. Android之自定义checkbox并解决内容和复选框之间的具体问题
  8. 关于页面之间局部显示的几种方式
  9. 家里没有wifi6设备,换wifi6路由器会有提升吗?
  10. Visual Studio 2015离线版msdn下载和安装
  11. oracle exadata效果,exadata成功案例与性能测试-oracle.pdf
  12. 在淘宝,我如何做好一个项目的启动?
  13. 基于C#的图片浏览及显示功能(源码)
  14. 在padavan运行wifidog
  15. kettle读取hbase数据
  16. 【excel】定位列内差异/定位行内容差异单元格
  17. 可以在windows下预览SVG文件 SVG Explorer Extension
  18. 必修二英语计算机课文翻译,高中英语必修二unit3课文翻译.doc
  19. 【Java学习笔记】 网络编程04 优化字符串拼接:JSON
  20. 希捷和西数移动硬盘哪个好_西数和希捷的硬盘哪个好看完存储数据一目了然

热门文章

  1. 转: databasemetadata 无法获取数据库表备注的解决方法
  2. (转)es 聚合查询并返回每个组的数据
  3. javafx 打开新窗口_新的JMetro JavaFX 11兼容版本
  4. api 获取网络使用情况_您的API是什么情况?
  5. qt弹簧教程_弹簧启动执行器教程
  6. java 换行 运算符格式_Java代码样式运算符换行格式
  7. Neo4j导入:java.lang.IllegalStateException:不支持在单个导入中混合指定和未指定的组所有物...
  8. spicy命令_Spicy Spring:动态创建自己的BeanDefinition
  9. java中的jpa_JPA教程–在Java SE环境中设置JPA
  10. c 遍历文件 递归遍历_将递归文件系统遍历转换为流