java-doc-nio

NIO

NIO是Java提供的另一套IO系统。NIO支持面向缓冲区的,基于通道的IO操作。缓冲区用于容纳数据,通道表示打开的到I/O设备(例如文件或套接字)的连接。通常,为了使用NIO系统,需要获取用于连接I/O设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,根据需要输入或输出数据。

新老网络通信区别

新老网络通信区别

缓冲区

缓冲区是在java.nio包中定义的。所有缓冲区都是Buffer类的子类,Buffer类定义了对所有缓冲区都通用的核心功能:当前位置、界限和容量。当前位置是缓冲区中下一次发生读取和写入操作的索引,当前位置通过大多数读或写操作向前推进。界限是缓冲区中最后一个有效位置之后下一个位置的索引值。容量是缓冲区能够容纳的元素的数量。通常界限等于缓冲区的容量。Buffer类型还支持标记和重置。

  • Buffer类定义的方法
方法 描述
abstract Object array() 如果调用缓冲区是基于数组的,就返回对数组的引用,否则抛出UnsupportedOperationException异常;如果数组是只读的,就抛出ReadOnlyBufferException异常
abstract int arrayOffset() 如果调用缓冲区是基于数组的,就返回第一个元素的索引,否则抛出UnspportedOperationException异常;如果数组是只读的,就抛出ReadOnlyBufferException异常
final int capacity() 返回调用缓冲区能够容纳的元素数量
final Buffer clear() 清空调用缓冲区并返回对缓冲区的引用
final Buffer flip() 将调用缓冲区的界限设置为当前位置,并将当前位置重置为0。返回对缓冲区的引用
abstract boolean hasArray() 如果调用缓冲区是基于读写数组的,就返回true;否则返回false
final boolean hasRemaining() 如果在调用缓冲区中还有剩余元素,就返回true;否则返回false
abstract boolean isDirect() 如果调用缓冲区是定向的,就返回true,这意味着可以直接对缓冲区进行IO操作;否则返回false
abstract boolean isReadOnly() 如果调用缓冲区是只读的,就返回true;否则返回false
final int limit() 返回调用缓冲区的界限
final Buffer() limit(int n) 将调用缓冲区的界限设置为n。返回对缓冲区的引用
final Buffer() mark() 对调用缓冲区设置标记并返回对调用缓冲区的引用
final int position() 返回当前位置
final Buffer position(int n) 将调用缓冲区的当前位置设置为n。返回对缓冲区的引用
int remaining() 返回在到达界限之前可用元素的数量。换句话说,返回界限减去当前位置后的值
final Buffer reset() 将调用缓冲区的当前位置重置为当前的标记。返回对缓冲区的引用
final Buffer rewind() 将调用缓冲区的位置设置为0。返回对缓冲区的引用

通道

通道是由java.nio.channels包定义的。通道表示到I/O源或目标的打开的连接。通道实现了Channel接口并扩展了Closeable接口和AutoCloseable接口。

  • FileChannel定义方法
方法 描述
abstract int read(ByteBuffer bb) 从调用通道读取字节到bb中,知道缓冲区已满或者不再有输入内容为止。返回实际读取的字节数,如果读到流的末尾,就返回-1
abstract int read(ByteBuffer bb, long start) 从start指定的文件位置开始,从调用通道读取字节到bb中,直到缓冲区已满或者不再输入内容为止。不改变当前位置。返回实际读取的字节数,如果start超出文件的末尾,就返回-1
abstract int write(ByteBuffer bb) 将bb的内容写入到通道,从当前位置开始。返回写入的字节数
abstract int write(ByteBuffer bb, long start) 从start指定的位置开始,将bb中的内容写入调用通道,不改变当前位置。返回写入的字节数

SeekableByteChannel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import java.io.IOException;
import java.nio.*;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class LearnChannel1
{
public static void main(String args[])
{
int count;

try(SeekableByteChannel fChan = Files.newByteChannel(Paths.get("test.txt"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE)){
ByteBuffer mBuf = ByteBuffer.allocate(128);

do {
count = fChan.read(mBuf);

if(count != -1) {
mBuf.rewind();

for(int i = 0; i < count; i++) {
System.out.print((char)mBuf.get());
}
}
} while(count != -1);

mBuf.rewind();
for(int i = 0; i < 128; i++) {
mBuf.put((byte)'A');
}

mBuf.rewind();
fChan.write(mBuf);

System.out.println();
} catch (InvalidPathException e) {
System.out.println("Path Error " + e);
} catch (IOException e) {
System.out.println("IO Error " + e);
}
}
}

MappedByteBuffer

映射的方式将数据映射到内存中缓冲区,映射的方式的好处是,对缓冲区的处理会自动同步文件中。

  • MapMode
说明
MapMode.READ_ONLY 只读
MapMode.READ_WRITE 读和写
MapMode.PRIVATE 创建私有副本,对缓冲区的修改不会影响到底层文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class LearnChannel2
{
public static void main(String args[])
{
try(FileChannel fChan = (FileChannel)Files.newByteChannel(Paths.get("test.txt"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE)){
long fSize = fChan.size();
MappedByteBuffer mBuf = fChan.map(FileChannel.MapMode.READ_WRITE, 0, fSize);

for(int i = 0; i < fSize; i++) {
System.out.print((char)mBuf.get());
}

mBuf.rewind();
for(int i = 0; i < 255; i++) {
mBuf.put((byte)i);
}


System.out.println();
} catch(InvalidPathException e) {
System.out.println("Path Error " + e);
} catch(IOException e) {
System.out.println("IO Error " + e);
}
}
}

Path

Path接口封装了文件的路径,描述了目录结构中文件的位置。

因为Path是接口,不是类,所以不能通过构造函数直接创建Path实例。但是,可以通过调用Path的静态方法返回Path实例。

  • Path接口定义的方法
方法 描述
boolean endsWith(String path) 如果调用Path对象以path指定的路径结束,就返回true;否则返回false
boolean endsWith(Path path) 如果调用path对象以path指定的路径结束,就返回true;否则返回false
Path getFileName() 返回与调用Path对象关联的文件名
Path getName(int idx) 返回的Path对象包含调用对象中由idx指定的路径元素的名称。最左边的元素位于0索引位置,这是离根路径最近的元素。最右边的元素getNameCount()-1索引位置
int getNameCount() 返回调用Path对象中根目录后面元素的数量
Path getParent() 返回的Path对象包含整个路径,但是不包含由调用Path对象指定的文件的名称
Path getRoot() 返回调用Path对象的根路径
boolean isAbsolute() 如果调用Path对象是绝对路径,就返回true;否则返回false
Path resolve(Path path) 如果path是绝对路径,就返回path;否则,如果path不包含根路径,就在path前面加上由调用Path对象指定的根路径,并返回结果。如果path为空,就返回调用Path对象;否则不对行为进行指定
Path resolve(String path) 如果path是绝对路径,就返回path;否则,如果path不包含根路径,就在path前面加上由调用Path对象指定的根路径,并返回结果。如果path为空,就返回调用Path对象 ;否则不对行为进行指定
boolean startsWith(String path) 如果调用Path对象以path指定的路径开始,就返回true;否则返回false
boolean startsWith(Path path) 如果调用Path对象以path指定的路径开始,就true;否则返回false
Path toAbsolutePath() 作为绝对路径返回调用Path对象
String toString() 返回调用Path对象的字符串表示形式
static Path get(String pathname, String … parts) 如果没有使用parts,就必须通过pathname以整体来指定路径。如果使用了parts,那么可以分块穿度路径
static Path get(URI url) 返回与uri对应的Path对象

Files

Files类提供了许多对文件操作的静态方法。

  • Files类定义的方法
方法 描述
static Path copy(Path src, Path dest, CopyOption … how) 将src指定的文件复制到dest指定的位置。参数how指定了复制是如果发生的
static Path createDirectory(Path path, FileAttribute<?> … attrs) 创建一个目录,path指定了该目录的路径,目录属性是由attribs指定的
static Path createFile(Path path, FileAttribute<?> … attribs) 创建一个文件,path指定了该文件的路径。文件属性是由attribs指定的
static void delete(Path path) 删除一个文件,path指定了该文件的路径
static boolean exists(Path path, LinkOption … opts) 如果path指定的文件存在,就返回true;否则返回false。如果没有指定opts,就使用符号链接。为了阻止符号链接,可以为opts传递NOFOLLOW_LINKS
static boolean isDirectory(Path path, LinkOption … opts) 如果path指定的是目录,就返回true;否则返回false。如果没有指定opts,就使用符号链接。为了阻止符号链接 ,可以为opts传递NOFOLLOW_LINKS
static boolean isExecutable(Path path) 如果path指定的是可执行文件,就返回true;否则返回false
static boolean isHidden(Path path) 如果path指定的文件是隐藏的,就返回true;否则返回false
static boolean isReadable(Path path) 如果path指定的文件是可读的,就返回true;否则返回false
static boolean isRegularFile(Path path, LinkOption … opts) 如果path指定的是文件,就返回true;否则返回false。如果没有指定opts,就使用符号链接。为了阻止符号链接,可以为opts传递NOFOLLOW_LINKS
static boolean isWritable(Path path) 如果path指定的文件是可写的,就返回true;否则返回false
static Path move(Path src, Path dest, CopyOption … how) 将src指定的文件移到dest指定的位置。参数how指定了文件移到是如果发生的
static SeekableByteChannel newByteChannel(Path path, OpenOption … how) 打开path指定的文件,how指定了打开方式。返回一个链接到该文件的SeekableByteChannel对象。这是一个可以改变当前位置的字节通道。FileChannel类实现了SeekableByteChannel方法
static DirectoryStream newDirectoryStream(Path path) 打开path指定的目录。返回一个链接到该目录的DirectoryStream对象
static InputStream newInputStream(Path path, OpenOption … how) 打开path指定的文件,how指定了打开方式。返回一个链接到该文件的InputStream对象
static OutputStream newOutputStream(Path path, Openoption … how) 打开path指定的文件,how指定了打开方式。返回一个链接到该文件的OutputStream对象
static boolean noExists(Path path. LinkOption … opts) 如果path指定的文件不存在,就返回true;否则返回false。如果没有指定opts,就使用符号链接。为了阻止符号链接,可以为opts传递NOFOLLOW_LINKS
static A readAttributes(Path path, Class attribType, LinkOption … opts) 获取与path指定的文件相关联的属性。获取的属性类型是由attibType传递的。如果没有指定opts,就是有符号链接。为了阻止符号链接,可以为opts传递NOFOLLOW_LINKS
static long size(Path path) 返回由path指定的文件的大小
  • 标准的文件打开选项
含义
APPEND 导致输出被写入文件末尾
CREATE 如果文件不存在,就创建文件
CREATE_NEW 只有当文件不存在时才创建文件
DELETE_ON_CLOSE 当文件被关闭时就删除文件
DSYNC 导致对文件的修改被立即写入物理文件。正常情况下,处于效率考虑,对文件的修改由文件系统进行缓冲,只有到需要时才写入文件中
READ 为输入操作打开文件
SPARSE 指示文件系统————文件是稀疏的,这意味着文件中可能没有完全填满数据。如果文件系统不支持稀疏文件,那么会忽略该选项
SYNC 导致对文件或文件中元数据的修改被立即写入物理文件。正常情况下,处于效率考虑,对文件的修改由文件系统进行缓冲,只有当需要时才写入文件
TRUNCATE_EXISTING 作为输出操作而打开的、之前旧存在的文件的长度减少到0
WRITE 为输出操作打开文件
  • StandardCopyOption
方法 描述
COPY_ATTRIBUTES 要求复制文件的属性
NOFOLLOW_LINKS 不使用符号链接
REPLACE_EXISTING 覆盖先前存在的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

public class LearnFiles1
{
public static void main(String args[])
{
int i ;

try(InputStream fin = Files.newInputStream(Paths.get("in.txt"))){
try (OutputStream fout = new BufferedOutputStream(Files.newOutputStream(Paths.get("out.txt")))){
do {
i = fin.read();
if(i != -1) {
System.out.print((char)i);
fout.write(i);
}
} while(i != -1);
}
} catch (IOException e) {
System.out.println("IO Error " + e);
}
}
}

BasicFileAttributes

BasicFileAttributes接口封装了在格子文件系统中都通用的一组属性。

  • BasicFileAttributes接口定义的方法
方法 描述
FileTime creationTime() 返回文件的创建时间。如果文件系统没有提供创建时间,就反回一个依赖于实现的时间值
Object fileKey() 返回文件键。如果不支持,就返回null
boolean isDirectory() 如果文件表示目录,就返回true
boolean isOther() 如果文件不是文件、符号链接或目录,就返回true
boolean isRegularFile() 如果文件是常规文件,而不是目录或符号链接,就返回true
boolean isSymbolicLink() 如果文件是符号链接,就返回true
FileTime lastAccessTime() 返回文件的最后一次访问时间。如果文件系统没有提供最后访问时间,就返回一个依赖于实现的时间值
FileTime lastModifiedTime() 返回文件的最后一次修改时间。如果文件系统没有提供最后一次修改时间,就返回一个依赖于实现的时间值
long size() 返回文件的大小

DosFileAttributes

DosFileAttributes实现了BasicFileAttributes接口,描述了与FAT文件系统相关的文件属性。

  • DosFileAttributes接口定义的方法
方法 描述
boolean isArchive() 如果文件被标记为存档文件,就返回true;否则返回false
boolean isHiddem() 如果文件是隐藏的,就返回true;否则返回false
boolean isReadOnly() 如果文件是只读的,就返回true;否则返回false
boolean isSystem() 如果文件被标记为系统文件,就返回true;否则返回false

PosixFileAttributes

PosixFileAttributes封装了POSIX标准定义的属性

  • PosixFileAttributes接口定义的方法
方法 描述
GroupPrincipal group() 返回文件组拥有者
UserPrincipal owner() 返回文件的拥有者
Set permissions() 返回文件的权限

DirectoryStream

DirectoryStream用于获取目录的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;

public class LearnDirectoryStream1
{
public static void main(String args[])
{
String dirname = "./";

try(DirectoryStream<Path> dirstrm = Files.newDirectoryStream(Paths.get(dirname))){
System.out.println("Directory of " + dirname);

for(Path entry : dirstrm) {
BasicFileAttributes attribs = Files.readAttributes(entry, BasicFileAttributes.class);

if(attribs.isDirectory()) {
System.out.print("<DIR>");
} else {
System.out.print(" ");
}

System.out.println(entry.getName(1));
}

} catch(IOException e) {
System.out.println("IOError " + e );
}
}
}

FileVisitor

FileVisitor用于遍历目录树,并且支持访问目录信息。

  • FileVisitor接口定义的方法
方法 描述
FileVisitResult postVisitDirectory(T dir, IOException exc) 在访问目录之后调用。目录被传递给dir,任何IOException异常都会被传递给exc。如果exc为null,就表示没有发生任何异常。结果被返回
FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attribs) 在访问目录之前调用。目录被传递给dir,与目录关联的属性被传递给attribs。结果被返回。为了继续检查目录,返回FileVisitResult.CONTINUE
FileVisitResult visitFile(T file, BasicFileAttributes attribs) 当访问文件时调用。文件被传递给file,与文件关联的属性被传递给attribs。结果被返回
FileVisitResult visitFileFailed(T file, IOException exc) 当尝试访问文件失败时调用,访问失败的文件由file传递,IOException异常由exc传递。结果被返回
  • FileVisitResult
含义
CONTINUE 继续遍历目录和子目录
SKIP_SIBLINGS 绕过目录及其子目录并阻止调用postVisitDirectory()方法
SKIP_SUBTREE 只绕过目录及其纸目录
TERMINATE 停止目录遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

class MyFileVisitor extends SimpleFileVisitor<Path>
{
public FileVisitResult visitFile(Path path, BasicFileAttributes attribs) throws IOException
{
System.out.println(path);
return FileVisitResult.CONTINUE;
}
}

public class LearnFileVisitor1
{
public static void main(String args[])
{
String dirname = "./";

System.out.println("Directory tree starting with " + dirname + ":\n");

try {
Files.walkFileTree(Paths.get(dirname), new MyFileVisitor());
} catch (IOException exc) {
System.out.println("IO Error " + exc);
}
}
}