java NIO系列教程2
7.FileChannel
Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。
FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。
打开FileChannel
在使用FileChannel之前,必须先打开它。但是,我们无法直接打开一个FileChannel,需要通过使用一个InputStream、OutputStream或RandomAccessFile来获取一个FileChannel实例。下面是通过RandomAccessFile打开FileChannel的示例:
1 |
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt","rw"); |
2 |
FileChannel inChannel = aFile.getChannel(); |
从FileChannel读取数据
调用多个read()方法之一从FileChannel中读取数据。如:
1 |
ByteBuffer buf = ByteBuffer.allocate(48); |
2 |
int bytesRead = inChannel.read(buf); |
首先,分配一个Buffer。从FileChannel中读取的数据将被读到Buffer中。
然后,调用FileChannel.read()方法。该方法将数据从FileChannel读取到Buffer中。read()方法返回的int值表示了有多少字节被读到了Buffer中。如果返回-1,表示到了文件末尾。
向FileChannel写数据
使用FileChannel.write()方法向FileChannel写数据,该方法的参数是一个Buffer。如:
01 |
String newData = "New String to write to file..." + System.currentTimeMillis(); |
02 |
03 |
ByteBuffer buf = ByteBuffer.allocate(48); |
04 |
buf.clear(); |
05 |
buf.put(newData.getBytes()); |
06 |
07 |
buf.flip(); |
08 |
09 |
while(buf.hasRemaining()) { |
10 |
channel.write(buf); |
11 |
} |
注意FileChannel.write()是在while循环中调用的。因为无法保证write()方法一次能向FileChannel写入多少字节,因此需要重复调用write()方法,直到Buffer中已经没有尚未写入通道的字节。
关闭FileChannel
用完FileChannel后必须将其关闭。如:
1 |
channel.close(); |
FileChannel的position方法
有时可能需要在FileChannel的某个特定位置进行数据的读/写操作。可以通过调用position()方法获取FileChannel的当前位置。
也可以通过调用position(long pos)方法设置FileChannel的当前位置。
这里有两个例子:
1 |
long pos = channel.position(); |
2 |
channel.position(pos +123); |
如果将位置设置在文件结束符之后,然后试图从文件通道中读取数据,读方法将返回-1 —— 文件结束标志。
如果将位置设置在文件结束符之后,然后向通道中写数据,文件将撑大到当前位置并写入数据。这可能导致“文件空洞”,磁盘上物理文件中写入的数据间有空隙。
FileChannel的size方法
FileChannel实例的size()方法将返回该实例所关联文件的大小。如:
1 |
long fileSize = channel.size(); |
FileChannel的truncate方法
可以使用FileChannel.truncate()方法截取一个文件。截取文件时,文件将中指定长度后面的部分将被删除。如:
1 |
channel.truncate(1024); |
这个例子截取文件的前1024个字节。
FileChannel的force方法
FileChannel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。
force()方法有一个boolean类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上。
下面的例子同时将文件数据和元数据强制写到磁盘上:
1 |
channel.force(true); |
8.
Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下2种方式创建SocketChannel:
- 打开一个SocketChannel并连接到互联网上的某台服务器。
- 一个新连接到达ServerSocketChannel时,会创建一个SocketChannel。
打开 SocketChannel
下面是SocketChannel的打开方式:
1 |
SocketChannel socketChannel = SocketChannel.open(); |
2 |
socketChannel.connect(new InetSocketAddress("http://jenkov.com",80)); |
关闭 SocketChannel
当用完SocketChannel之后调用SocketChannel.close()关闭SocketChannel:
1 |
socketChannel.close(); |
从 SocketChannel 读取数据
要从SocketChannel中读取数据,调用一个read()的方法之一。以下是例子:
1 |
ByteBuffer buf = ByteBuffer.allocate(48); |
2 |
int bytesRead = socketChannel.read(buf); |
首先,分配一个Buffer。从SocketChannel读取到的数据将会放到这个Buffer中。
然后,调用SocketChannel.read()。该方法将数据从SocketChannel 读到Buffer中。read()方法返回的int值表示读了多少字节进Buffer里。如果返回的是-1,表示已经读到了流的末尾(连接关闭了)。
写入 SocketChannel
写数据到SocketChannel用的是SocketChannel.write()方法,该方法以一个Buffer作为参数。示例如下:
01 |
String newData = "New String to write to file..." + System.currentTimeMillis(); |
02 |
03 |
ByteBuffer buf = ByteBuffer.allocate(48); |
04 |
buf.clear(); |
05 |
buf.put(newData.getBytes()); |
06 |
07 |
buf.flip(); |
08 |
09 |
while(buf.hasRemaining()) { |
10 |
channel.write(buf); |
11 |
} |
注意SocketChannel.write()方法的调用是在一个while循环中的。Write()方法无法保证能写多少字节到SocketChannel。所以,我们重复调用write()直到Buffer没有要写的字节为止。
非阻塞模式
可以设置 SocketChannel 为非阻塞模式(non-blocking mode).设置之后,就可以在异步模式下调用connect(), read() 和write()了。
connect()
如果SocketChannel在非阻塞模式下,此时调用connect(),该方法可能在连接建立之前就返回了。为了确定连接是否建立,可以调用finishConnect()的方法。像这样:
1 |
socketChannel.configureBlocking(false); |
2 |
socketChannel.connect(new InetSocketAddress("http://jenkov.com",80)); |
3 |
4 |
while(! socketChannel.finishConnect() ){ |
5 |
//wait, or do something else... |
6 |
} |
write()
非阻塞模式下,write()方法在尚未写出任何内容时可能就返回了。所以需要在循环中调用write()。前面已经有例子了,这里就不赘述了。
read()
非阻塞模式下,read()方法在尚未读取到任何数据时可能就返回了。所以需要关注它的int返回值,它会告诉你读取了多少字节。
非阻塞模式与选择器
非阻塞模式与选择器搭配会工作的更好,通过将一或多个SocketChannel注册到Selector,可以询问选择器哪个通道已经准备好了读取,写入等。Selector与SocketChannel的搭配使用会在后面详讲。
java NIO系列教程2的更多相关文章
- Java NIO系列教程(八)JDK AIO编程
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
- Java NIO系列教程(七) selector原理 Epoll版的Selector
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
- Java NIO系列教程(三) Channel之Socket通道
目录: <Java NIO系列教程(二) Channel> <Java NIO系列教程(三) Channel之Socket通道> 在<Java NIO系列教程(二) Ch ...
- Java NIO系列教程(二) Channel通道介绍及FileChannel详解
目录: <Java NIO系列教程(二) Channel> <Java NIO系列教程(三) Channel之Socket通道> Channel是一个通道,可以通过它读取和写入 ...
- Java NIO系列教程(十一) Java NIO 与 IO
Java NIO系列教程(十一) Java NIO与IO 当学习了 Java NIO 和 IO 的 API 后,一个问题马上涌入脑海: 我应该何时使用 IO,何时使用 NIO 呢?在本文中,我会尽量清 ...
- Java NIO系列教程(十)DatagramChannel
Java NIO系列教程(十)DatagramChannel 转载自并发编程网 – ifeve.com,本文链接地址: Java NIO系列教程(十) Java NIO DatagramChannel
- Java NIO系列教程(四) Scatter 和 Gather
Java NIO系列教程(四) Scatter 和 Gather Java NIO 开始支持 scatter/gather,scatter/gather 用于描述从 Channel(译者注:Chann ...
- Java NIO系列教程(三-十二) Buffer
原文链接 作者:Jakob Jenkov 译者:airu 校对:丁一 Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到 ...
- Java NIO 系列教程(转)
原文中说了最重要的3个概念,Channel 通道Buffer 缓冲区Selector 选择器其中Channel对应以前的流,Buffer不是什么新东西,Selector是因为nio可以使用异步的非堵塞 ...
- 转:Java NIO系列教程(一)Java NIO 概述
Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Sel ...
随机推荐
- css控制英文内容自动换行問題
css控制英文内容自动换行 HTML: <!-- 因为要显示的内容是用户通过CMS添加进入数据库,再抓取出来前台显示的,所以你根本无法 控制每一行内容的长度. 所以我在显示内容的div设置了一个 ...
- App主导现在 HTML5领衔未来
HTML5能够让开发人员构建丰富的基于Web应用程序,使其能在任何设备中使用标准的Web浏览器.很多人认为HTML5将会让App过时.到底App还是HTML5会是谁赢得最后的胜利,在业界也有不少讨论, ...
- DBCC--SQLPERF
提供所有数据库的事务日志空间使用情况统计信息.也可以用于重置等待和闩锁的统计信息. 语法: DBCC SQLPERF ( [ LOGSPACE ] | [ "sys.dm_os_latch ...
- Nginx an upstream response is buffered to a temporary file
1.错误日志:warn:an upstream response is buffered to a temporary file 解决办法:增加fastcgi_buffers 8 4K; fa ...
- /bin/sh: cc: 未找到命令
redis 4安装出现 /bin/sh cc: 未找到命令 解决: yum -y install gcc automake autoconf libtool make
- RabbitMQ广播模式
广播模式:1对多,produce发送一则消息多个consumer同时收到.注意:广播是实时的,produce只负责发出去,不会管对端是否收到,若发送的时刻没有对端接收,那消息就没了,因此在广播模式下设 ...
- Docker之存储管理
本文由作者邹珍珍授权网易云社区发布. 本文主要介绍Docker的存储管理.Docker拥有镜像分层,写时复制机制以及内容寻址存储等特征,为了支持这些特征,Docker设计了一套镜像元数据管理机制来管理 ...
- Django 使用getattr() 方法获取配置文件的变量值
在django项目的开发过程中,有时需要获取配置文件里的变量值,可以通过下面这样的方式去进行获取 from django.conf import settings item = getattr(set ...
- python http post json
直接上代码吧 #coding=utf-8 import os import urllib import urllib2 import re import cookielib import json h ...
- 【wireshark】插件开发(一):概述
1. 概述 wireshark提供了灵活的插件机制,使用户可以方便地扩展wireshark的功能.插件的功能主要包括,但不限于协议解析器. 可以使用Lua或C语言来编写Wireshark插件,下表对比 ...