原文地址: link.
8.Java NIO FileChannel
Java NIO FileChannel是连接文件的通道。使用文件通道,你可以从文件中读取数据,并将数据写入文件。 Java NIO FileChannel类是NIO替代标准Java IO API来实现读取文件。
FileChannel无法设置为非阻塞模式。它始终以阻塞模式运行。
打开FileChannel
在使用FileChannel之前,必须先将其打开。你无法直接打开FileChannel。你需要通过InputStream,OutputStream或RandomAccessFile获取FileChannel。以下是通过RandomAccessFile打开FileChannel的方法:
RandomAccessFile aFile = new RandomAccessFile("data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
从FileChannel读取数据
要从FileChannel读取数据,可以调用其中的**read( )**方法。这是一个例子:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
首先分配缓冲区。从FileChannel读取的数据被读入Buffer。
其次,调用FileChannel.read( )方法。此方法将FileChannel中的数据读入 Buffer。read( )方法返回的int值得出缓冲区中有多少字节。如果返回-1,则到达文件结尾。
将数据写入FileChannel
使用FileChannel.write( )方法将数据写入FileChannel,该方法将Buffer作为参数。这是一个例子:
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
channel.write(buf);
}
注意如何在while循环中调用FileChannel.write( )方法。无法保证write( )方法写入FileChannel的字节数。因此我们重复write( )调用,直到Buffer中没有其他字节要写入。
关闭FileChannel
当你完成使用时,你必须关闭FileChannel。这是如何做到的:
channel.close();
FileChannel Position
在读取或写入FileChannel时,你可以在特定位置执行此操作。你可以通过调用position( )方法获取FileChannel对象的当前位置。
你还可以通过调用position(long pos)方法来设置FileChannel的位置。
这是两个例子:
long pos = channel.position();
channel.position(pos +123);
如果你在文件结束后设置位置,并尝试从通道读取,你将得到-1——文件结束标记。
如果在文件结束后设置位置并写入通道,则文件将扩展以适合位置并写入数据。这可能导致“文件漏洞”,其中磁盘上的物理文件在写入数据中存在间隙。
FileChannel 大小
FileChannel对象的size( )方法返回通道所连接文件的文件大小。这是一个简单的例子:
long fileSize = channel.size();
FileChannel 截断
你可以通过调用FileChannel.truncate( )方法截断文件。截断文件时,会以给定长度将其剪切掉。这是一个例子:
channel.truncate(1024);
此示例以1024字节的长度截断文件。
FileChannel Force
FileChannel.force( )方法将所有未写入的数据从通道刷新到磁盘。出于性能原因,操作系统可能会将数据缓存在内存中,因此在调用该force( )方法之前,无法保证写入通道的数据实际写入磁盘。
force( )方法采用布尔值作为参数,告知是否应该刷新文件元数据(权限等)。
这是一个刷新数据和元数据的示例:
channel.force(true);
9.Java NIO SocketChannel
Java NIO SocketChannel是连接到TCP网络套接字的通道。它是Java NIO相当于Java Networking的套接字。有两种方法可以创建SocketChannel:
- 打开SocketChannel并连接到Internet上的某个服务器。
- 当传入连接到达ServerSocketChannel时,可以创建SocketChannel。
打开SocketChannel
以下是打开的方式SocketChannel方式:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
关闭SocketChannel
在使用后通过调用SocketChannel.close( )方法关闭SocketChannel。这是如何做到的:
socketChannel.close();
从SocketChannel读取
要从SocketChannel读取数据可以调用其中的read( )方法。这是一个例子:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);
首先分配缓冲区。从中SocketChannel读取的数据被读入Buffer。
其次,调用SocketChannel.read( )方法。此方法将数据从SocketChannel读入Buffer。read( )方法返回的int值得到缓冲区中有多少字节。如果返回-1,则到达流末尾(连接已关闭)。
写入SocketChannel
使用SocketChannel.write( )方法将数据写入SocketChannel,该方法将Buffer作为参数。这是一个例子:
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
channel.write(buf);
}
注意如何在while循环中调用SocketChannel.write( )方法。无法保证write( )方法写入SocketChannel的字节数。因此我们重复write( )调用,直到Buffer中没有其他字节要写入。
非阻塞模式
你可以将SocketChannel设置为非阻塞模式。执行此操作时,可以在异步模式下调用connect( ),read( )和write( )。
connect( )
如果SocketChannel处于非阻塞模式,并且你调用connect( ),则该方法可能会在建立连接之前返回。要确定是否已建立连接,可以调用finishConnect()方法,如下所示:
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
while(! socketChannel.finishConnect() ){
//wait, or do something else...
}
write( )
在非阻塞模式下,write( )方法可能在没有写入任何内容的情况下返回。因此,需要在循环中调用write( )方法。但是,由于这已经在之前的编写示例中完成,因此不需要在此处做任何不同的操作。
read( )
在非阻塞模式下,read( )方法可能在没有读取任何数据的情况下返回。因此,需要注意返回的int,它告诉读取了多少字节。
带Selector的非阻塞模式
使用Selector时,SocketChannel的非阻塞模式效果更好。通过使用选择器注册一个或多个SocketChannel,可以向选择器询问准备好读取,写入等的通道。如何在SocketChannel中使用Selector,将在本教程的后续文章中详细介绍。
【上篇】Java NIO学习教程(三)==>点击
【下篇】Java NIO学习教程(五)==>点击