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

新老网络通信区别
缓冲区
缓冲区是在java.nio包中定义的。所有缓冲区都是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接口。
方法 |
描述 |
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.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实例。
方法 |
描述 |
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类提供了许多对文件操作的静态方法。
方法 |
描述 |
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 |
为输出操作打开文件 |
方法 |
描述 |
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文件系统相关的文件属性。
方法 |
描述 |
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用于遍历目录树,并且支持访问目录信息。
方法 |
描述 |
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传递。结果被返回 |
值 |
含义 |
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); } } }
|