参考文献:
Reading, Writing, and Creating Files
Java nio 学习笔记(一) Buffer(缓冲区)与Channel(通道)的相关知识
Java NIO系列教程(七) FileChannel
POSIX文件及目录管理
概述
通常情况下,我们会觉得使用java操作文件io比较繁琐,java7 Files类提供了一系列io小工具也许会简化一些操作,如下:
方法 | 适用场景 |
---|---|
readAllBytes readAllLines |
适合小文件操作 |
newBufferedReader newBufferedWriter |
文本文件操作 |
newInputStream newOutputStream |
字节流操作,无需缓冲 |
newByteChannel newFileChannel |
使用通道和缓存进行底层流操作。底层特性,比如锁文件、内存映射操作 |
OpenOperations
写文件方法可以通过OpenOperations参数告诉系统当文件不存时候是报错还是新建、当前输出内容是追加还是覆盖等。下面是StandardOpenOptions所支持的文件操作方式:
枚举 | 说明 |
---|---|
WRITE | 简单的写文件,如果文件不存,会抛出异常。 |
TRUNCATE_EXISTING | 清空已有文件的数据。一般和WRITE搭配使用。 |
CREATE | 如果不存在就创建新文件。 |
CREATE_NEW | 如果不存在就创建新文件,如果文件以及存在就抛出异常。 |
APPEND | 想已有的文件中追加新数据,一般会和WRITE或者CREATE搭配使用。 |
DELETE_ON_CLOSE | 关闭文件时候删除文件,这个一般结合临时文件使用。 |
小文件
Path path = Paths.get("data/ref.txt");
byte[] bytes = Files.readAllBytes(path);
List<String> list = Files.readAllLines(path, Charset.forName("utf-8"));
byte[] bytes = "测试".getBytes("utf-8");
Path path = Paths.get("data/ref2.txt");
Files.write(path, bytes, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
文本文件
Path path = Paths.get("data/ref.txt");
try (BufferedReader bufferedReader = Files.newBufferedReader(path, Charset.forName("utf-8"))) {
String line = null;
while (null != (line = bufferedReader.readLine())) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
普通I/O流
Path path = Paths.get("data/ref.txt");
// 打开文件流
try (InputStream in = Files.newInputStream(path)) {
// 如果需要缓存,可以使用BufferedInputStream再包装一层
} catch (IOException e) {
e.printStackTrace();
}
通道和字节缓冲
流I/O一次性读取一个字符(字节),通道I/O一次性读取的是一个缓冲区。ByteChannel提供了基本的读和写方法,它的子类SeekableByteChannel接口拓展了一些特性,比如读取和设置当前字节起始位置(用于随机访问)、截取文件内容(从后向前进行)、查询文件大小。FileChannel抽象类实现了该接口。
下面是读取字节位置和字节内容的例子:
// 默认是只读模式
try (SeekableByteChannel sbc = Files.newByteChannel(path)) {
ByteBuffer buf = ByteBuffer.allocate(3);
String encoding = System.getProperty("file.encoding");
System.out.println("encoding=" + encoding);
while (sbc.read(buf) > 0) {
// 当前字节起始位置
long position = sbc.position();
System.out.println("current position = " + position);
buf.rewind();
System.out.println(Charset.forName(encoding).decode(buf));
buf.flip();
}
} catch (IOException x) {
System.out.println("caught exception: " + x);
}
下面是获取文件大小和截取文件的例子:
// 默认是读取权限,如果需要截取,需要指明Operation为APPEND
try (SeekableByteChannel sbc = Files.newByteChannel(path, APPEND)) {
long size = sbc.size();
System.out.println("size of file = " + size + " bytes");
// 截取文件内容,如果要清空文件,请输入0
sbc.truncate(0);
} catch (IOException x) {
System.out.println("caught exception: " + x);
}
创建UNIX(POSIX)文件
Set<OpenOption> options = new HashSet<OpenOption>();
options.add(APPEND);
options.add(CREATE);
// 权限
Set<PosixFilePermission> perms =
PosixFilePermissions.fromString("rw-r-----");
FileAttribute<Set<PosixFilePermission>> attr =
PosixFilePermissions.asFileAttribute(perms);
String s = "Hello World! ";
byte data[] = s.getBytes();
ByteBuffer bb = ByteBuffer.wrap(data);
Path file = Paths.get("data/ref.txt");
try (SeekableByteChannel sbc =
Files.newByteChannel(file, options, attr)) {
sbc.write(bb);
} catch (IOException x) {
System.out.println("Exception thrown: " + x);
}
创建临时文件
有了createTempFile()方法,再配合DELETE_ON_CLOSE选项,轻松实现某些特定场景(比如从远程ftp读取大文件,缓存到本地磁盘,然后解释读取后删除)。
Path path = Paths.get("data");
try {
// 指定文件的目录
Path tempFile = Files.createTempFile(path, null, ".tmp");
System.out.format("The temporary file" + " has been created: %s%n", tempFile);
// 关闭后删除文件
try (InputStream in = Files.newInputStream(tempFile, DELETE_ON_CLOSE)) {
}
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
}