在丑陋的 Java I/O 编程方式诞生多年以后,Java终于简化了文件读写的基本操作。

两个基本组件

  1. 文件或者目录的路径;
  2. 文件本身。

这块基本都是些记忆性的东西,没什么过多的需要写的地方,用的时候搜一下就好,记住当然好,但是本人智商记不住。并且只看看NIO就可以。

文件系统

// files/FileSystemDemo.java
import java.nio.file.*; public class FileSystemDemo {
static void show(String id, Object o) {
System.out.println(id + ": " + o);
} public static void main(String[] args) {
System.out.println(System.getProperty("os.name"));
FileSystem fsys = FileSystems.getDefault();
for(FileStore fs : fsys.getFileStores())
show("File Store", fs);
for(Path rd : fsys.getRootDirectories())
show("Root Directory", rd);
show("Separator", fsys.getSeparator());
show("UserPrincipalLookupService",
fsys.getUserPrincipalLookupService());
show("isOpen", fsys.isOpen());
show("isReadOnly", fsys.isReadOnly());
show("FileSystemProvider", fsys.provider());
show("File Attribute Views",
fsys.supportedFileAttributeViews());
}
}
/* 输出:
Windows 10
File Store: SSD (C:)
Root Directory: C:\
Root Directory: D:\
Separator: \
UserPrincipalLookupService:
sun.nio.fs.WindowsFileSystem$LookupService$1@15db9742
isOpen: true
isReadOnly: false
FileSystemProvider:
sun.nio.fs.WindowsFileSystemProvider@6d06d69c
File Attribute Views: [owner, dos, acl, basic, user]
*/

路径监听

通过 WatchService 可以设置一个进程对目录中的更改做出响应。在这个例子中,delTxtFiles() 作为一个单独的任务执行,该任务将遍历整个目录并删除以 .txt 结尾的所有文件,WatchService 会对文件删除操作做出反应:

// files/PathWatcher.java
// {ExcludeFromGradle}
import java.io.IOException;
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
import java.util.concurrent.*; public class PathWatcher {
static Path test = Paths.get("test"); static void delTxtFiles() {
try {
Files.walk(test)
.filter(f ->
f.toString()
.endsWith(".txt"))
.forEach(f -> {
try {
System.out.println("deleting " + f);
Files.delete(f);
} catch(IOException e) {
throw new RuntimeException(e);
}
});
} catch(IOException e) {
throw new RuntimeException(e);
}
} public static void main(String[] args) throws Exception {
Directories.refreshTestDir();
Directories.populateTestDir();
Files.createFile(test.resolve("Hello.txt"));
WatchService watcher = FileSystems.getDefault().newWatchService();
test.register(watcher, ENTRY_DELETE);
Executors.newSingleThreadScheduledExecutor()
.schedule(PathWatcher::delTxtFiles,
250, TimeUnit.MILLISECONDS);
WatchKey key = watcher.take();
for(WatchEvent evt : key.pollEvents()) {
System.out.println("evt.context(): " + evt.context() +
"\nevt.count(): " + evt.count() +
"\nevt.kind(): " + evt.kind());
System.exit(0);
}
}
}
/* Output:
deleting test\bag\foo\bar\baz\File.txt
deleting test\bar\baz\bag\foo\File.txt
deleting test\baz\bag\foo\bar\File.txt
deleting test\foo\bar\baz\bag\File.txt
deleting test\Hello.txt
evt.context(): Hello.txt
evt.count(): 1
evt.kind(): ENTRY_DELETE
*/

文件查找

到目前为止,为了找到文件,我们一直使用相当粗糙的方法,在 path 上调用 toString(),然后使用 string 操作查看结果。事实证明,java.nio.file 有更好的解决方案:通过在 FileSystem 对象上调用 getPathMatcher() 获得一个 PathMatcher,然后传入您感兴趣的模式。模式有两个选项:glob 和 regexglob 比较简单,实际上功能非常强大,因此您可以使用 glob 解决许多问题。如果您的问题更复杂,可以使用 regex,这将在接下来的 Strings 一章中解释。

在这里,我们使用 glob 查找以 .tmp 或 .txt 结尾的所有 Path

// files/Find.java
// {ExcludeFromGradle}
import java.nio.file.*; public class Find {
public static void main(String[] args) throws Exception {
Path test = Paths.get("test");
Directories.refreshTestDir();
Directories.populateTestDir();
// Creating a *directory*, not a file:
Files.createDirectory(test.resolve("dir.tmp")); PathMatcher matcher = FileSystems.getDefault()
.getPathMatcher("glob:**/*.{tmp,txt}");
Files.walk(test)
.filter(matcher::matches)
.forEach(System.out::println);
System.out.println("***************"); PathMatcher matcher2 = FileSystems.getDefault()
.getPathMatcher("glob:*.tmp");
Files.walk(test)
.map(Path::getFileName)
.filter(matcher2::matches)
.forEach(System.out::println);
System.out.println("***************"); Files.walk(test) // Only look for files
.filter(Files::isRegularFile)
.map(Path::getFileName)
.filter(matcher2::matches)
.forEach(System.out::println);
}
}
/* Output:
test\bag\foo\bar\baz\5208762845883213974.tmp
test\bag\foo\bar\baz\File.txt
test\bar\baz\bag\foo\7918367201207778677.tmp
test\bar\baz\bag\foo\File.txt
test\baz\bag\foo\bar\8016595521026696632.tmp
test\baz\bag\foo\bar\File.txt
test\dir.tmp
test\foo\bar\baz\bag\5832319279813617280.tmp
test\foo\bar\baz\bag\File.txt
***************
5208762845883213974.tmp
7918367201207778677.tmp
8016595521026696632.tmp
dir.tmp
5832319279813617280.tmp
***************
5208762845883213974.tmp
7918367201207778677.tmp
8016595521026696632.tmp
5832319279813617280.tmp
*/

在 matcher 中,glob 表达式开头的 **/ 表示“当前目录及所有子目录”,这在当你不仅仅要匹配当前目录下特定结尾的 Path 时非常有用。单 * 表示“任何东西”,然后是一个点,然后大括号表示一系列的可能性---我们正在寻找以 .tmp 或 .txt 结尾的东西。您可以在 getPathMatcher() 文档中找到更多详细信息。

matcher2 只使用 *.tmp,通常不匹配任何内容,但是添加 map() 操作会将完整路径减少到末尾的名称。

注意,在这两种情况下,输出中都会出现 dir.tmp,即使它是一个目录而不是一个文件。要只查找文件,必须像在最后 files.walk() 中那样对其进行筛选。

文件读写

文件很小的话

// files/ListOfLines.java
import java.util.*;
import java.nio.file.*; public class ListOfLines {
public static void main(String[] args) throws Exception {
Files.readAllLines(
Paths.get("../streams/Cheese.dat"))
.stream()
.filter(line -> !line.startsWith("//"))
.map(line ->
line.substring(0, line.length()/2))
.forEach(System.out::println);
}
}
/* Output:
Not much of a cheese
Finest in the
And what leads you
Well, it's
It's certainly uncon
*/

跳过注释行,其余的内容每行只打印一半。 这实现起来很简单:你只需将 Path 传递给 readAllLines() (以前的 java 实现这个功能很复杂)。readAllLines() 有一个重载版本,包含一个 Charset 参数来存储文件的 Unicode 编码。

// files/Writing.java
import java.util.*;
import java.nio.file.*; public class Writing {
static Random rand = new Random(47);
static final int SIZE = 1000; public static void main(String[] args) throws Exception {
// Write bytes to a file:
byte[] bytes = new byte[SIZE];
rand.nextBytes(bytes);
Files.write(Paths.get("bytes.dat"), bytes);
System.out.println("bytes.dat: " + Files.size(Paths.get("bytes.dat"))); // Write an iterable to a file:
List<String> lines = Files.readAllLines(
Paths.get("../streams/Cheese.dat"));
Files.write(Paths.get("Cheese.txt"), lines);
System.out.println("Cheese.txt: " + Files.size(Paths.get("Cheese.txt")));
}
}
/* Output:
bytes.dat: 1000
Cheese.txt: 199
*/

如果文件大小有问题怎么办? 比如说:

  1. 文件太大,如果你一次性读完整个文件,你可能会耗尽内存。

  2. 您只需要在文件的中途工作以获得所需的结果,因此读取整个文件会浪费时间。

Files.lines() 方便地将文件转换为行的 Stream

流是很快的,且可控,这个例子就蛮不错的

// files/StreamInAndOut.java
import java.io.*;
import java.nio.file.*;
import java.util.stream.*; public class StreamInAndOut {
public static void main(String[] args) {
try(
Stream<String> input =
Files.lines(Paths.get("StreamInAndOut.java"));
PrintWriter output =
new PrintWriter("StreamInAndOut.txt")
) {
input.map(String::toUpperCase)
.forEachOrdered(output::println);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}

切记,不要再用以前的java IO了,直接上手NIO,Files这个类很强

文件操作NIO的更多相关文章

  1. Java7 新特性 —— java.nio.file 文件操作

    本文部分摘自 On Java 8 自 Java7 开始,Java 终于简化了文件读写的基本操作,新增了 java.nio.file 库,通过与 Java8 新增的 stream 结合可以使得文件操作变 ...

  2. Java最全文件操作实例汇总

    本文实例汇总了Java文件操作.分享给大家供大家参考,具体如下: 1.创建文件夹 ? 1 2 3 4 5 6 7 8 9 10 11 //import java.io.*; File myFolder ...

  3. Java文件操作源码大全

    Java文件操作源码大全 1.创建文件夹 52.创建文件 53.删除文件 54.删除文件夹 65.删除一个文件下夹所有的文件夹 76.清空文件夹 87.读取文件 88.写入文件 99.写入随机文件 9 ...

  4. 笔记:I/O流-文件操作

    Java库中使用 Path 和 Files 类封装了在用户机器上处理文件系统所需要的所有功能,可以使用Paths来获取一个具体的Path对象,来表示具体的路径. 路径 Path表示的是一个目录名序列, ...

  5. JDK 7中的文件操作的新特性

    文件系统综述 一个文件系统在某种媒介(通常是一个或多个硬盘)上存储和组织文件.如今的大多数文件系统都是以树状结构来存储文件.在树的顶端是一个或多个根节点,在根节点一下,是文件和目录(在Windows系 ...

  6. Java文件操作类效率对比

    前言 众所周知,Java中有多种针对文件的操作类,以面向字节流和字符流可分为两大类,这里以写入为例: 面向字节流的:FileOutputStream 和 BufferedOutputStream 面向 ...

  7. 第11讲-Java泛型和文件操作

    1.知识点 1.1.课程回顾 1.2.本章重点 1.2.1.泛型 1.2.2.文件操作 2.具体内容 2.1.Java泛型 2.1.1.为什么需要泛型 我们发现在List中,底层是Object[ ]数 ...

  8. 【.NET深呼吸】Zip文件操作(1):创建和读取zip文档

    .net的IO操作支持对zip文件的创建.读写和更新.使用起来也比较简单,.net的一向作风,东西都准备好了,至于如何使用,请看着办. 要对zip文件进行操作,主要用到以下三个类: 1.ZipFile ...

  9. 野路子出身PowerShell 文件操作实用功能

    本文出处:http://www.cnblogs.com/wy123/p/6129498.html 因工作需要,处理一批文件,本想写C#来处理的,后来想想这个是PowerShell的天职,索性就网上各种 ...

随机推荐

  1. SQLserver还原失败(数据库正在使用,无法获得对数据库的独占访问权)

    问题描述: Sql server还原失败(数据库正在使用,无法获得对数据库的独占访问权) 数据库还原的时候还有其他进程连在上面,导致无法获得独占造成的. 这个问题的原因在于有用户连接了当前要做还原的数 ...

  2. Serverless 实战——使用 Rendertron 搭建 Headless Chrome 渲染解决方案

    为什么需要 Rendertron? 传统的 Web 页面,通常是服务端渲染的,而随着 SPA(Single-Page Application) 尤其是 React.Vue.Angular 为代表的前端 ...

  3. CAS与ABA问题产生和优雅解决

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  4. win10下配置python环境变量(Python配置环境变量)

    从官网下载Windows下的python版本,一路按照默认进行安装. 安装之后配置环境变量的步骤如下: 1,点“我的电脑”,右键选“属性”. 2,选择“高级系统设置”--->选“环境变量”--- ...

  5. CSRF漏洞原理浅谈

    CSRF漏洞原理浅谈 By : Mirror王宇阳 E-mail : mirrorwangyuyang@gmail.com 笔者并未深挖过CSRF,内容居多是参考<Web安全深度剖析>.& ...

  6. SAP FI 问题汇总

    记录工作中遇到的问题汇总 1.固定资产折旧码的设置 2.与资产有关的日期 3.如何添加固定资产分类

  7. win10,7 80端口被占用的检测和解决方法

    这是一篇关于检测windows7和windows10系统“80端口”被哪个程序占用和怎么解决的小教程.此处用windows10作为范例 1.得到占用该端口的PID ①打开运行(快捷键win+R)(也可 ...

  8. 将CocoStudio产生的UI文件导入到项目

    配置: Xcode 6.0 + CocoStudio 1.6 + Cocos2d-x 3.4 添加资源 将导出的资源文件放到 Resource 文件夹下. 头文件 #include "coc ...

  9. Matlab线性规划

    线性规划   线性规划的标准形式 \[\underset{x}{min}{\ c^Tx}\ s.t.\ Ax \leqslant b\]   例如,线性规划为: \[ \underset{x}{min ...

  10. TYUT程序设计入门第四讲练习题题解--数论入门

    程序设计入门第四讲练习题题解--数论入门 对于新知识点的学习,需要不断地刷题训练,才能有所收获,才能更好地消化知识点. 题组链接: 程序设计入门第四讲练习题--数论 by vjudge 题解: A. ...