java nio使用样例_Java NIO系列使用示例

本文详细介绍了Java NIO的各种使用示例,包括文件读写、客户端和服务端Socket通信、DatagramChannel的使用,以及Pipe的创建与数据传输。通过这些示例,读者可以深入理解Java NIO在实际开发中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 packagecom.nio.test;2

3 importjava.io.IOException;4 importjava.io.RandomAccessFile;5 importjava.net.InetSocketAddress;6 importjava.nio.ByteBuffer;7 importjava.nio.CharBuffer;8 importjava.nio.channels.DatagramChannel;9 importjava.nio.channels.FileChannel;10 importjava.nio.channels.Pipe;11 importjava.nio.channels.ServerSocketChannel;12 importjava.nio.channels.SocketChannel;13 importjava.nio.charset.Charset;14 importjava.nio.charset.CharsetDecoder;15 importjava.nio.charset.CoderResult;16 importjava.nio.file.Files;17 importjava.nio.file.LinkOption;18 importjava.nio.file.Path;19 importjava.nio.file.Paths;20

21 public classChannelTest {22 public static void main(String[] args) throwsException {23 newChannelTest().filewrite();24 newChannelTest().byteBufferUtf8();25 newChannelTest().fileread();26 newChannelTest().clientsocket();27 newChannelTest().serverSocket();28 newChannelTest().serverDatagram();29 newChannelTest().clientDatagram();30 newChannelTest().pipe();31 newChannelTest().NIOPath();32 }33

34 private voidfileread() {35 RandomAccessFile aFile;36 Charset charset = Charset.forName("UTF-8");37 CharsetDecoder decoder =charset.newDecoder();38 try{39 //在使用FileChannel之前,必须先打开它。但是,我们无法直接打开一个FileChannel,40 //需要通过使用一个InputStream、OutputStream或RandomAccessFile来获取一个FileChannel实例

41 aFile = new RandomAccessFile("src/com/nio/test/nio-data.txt", "rw");42

43 FileChannel inChannel =aFile.getChannel();44 //首先,分配一个Buffer。从FileChannel中读取的数据将被读到Buffer中。45 //create buffer with capacity of 48 byte

46 ByteBuffer byteBuffer = ByteBuffer.allocate(48);//read into buffer.

47 CharBuffer charBuffer = CharBuffer.allocate(48);48

49 //调用多个read()方法之一 从FileChannel中读取数据。

50 int bytesRead =inChannel.read(byteBuffer);51

52 char[] tmp = null; //临时存放转码后的字符

53 byte[] remainByte = null;//存放decode操作后未处理完的字节。decode仅仅转码尽可能多的字节,此次转码不了的字节需要缓存,下次再转

54 int leftNum = 0; //未转码的字节数

55

56 while (bytesRead != -1) {57

58 //System.out.println("Read " + bytesRead);

59 byteBuffer.flip(); //make buffer ready for read

60 decoder.decode(byteBuffer, charBuffer, false);61

62 charBuffer.flip();63

64 remainByte = null;65 leftNum = byteBuffer.limit() -byteBuffer.position();66 if (leftNum > 0) { //记录未转换完的字节

67 remainByte = new byte[leftNum];68 byteBuffer.get(remainByte, 0, leftNum);69 }70

71 //输出已转换的字符

72 tmp = new char[charBuffer.length()];73 while(charBuffer.hasRemaining()) {74 charBuffer.get(tmp);75 System.out.print(newString(tmp));76 }77

78 byteBuffer.clear(); //make buffer ready for writing

79 charBuffer.clear();80

81 if (remainByte != null) {82 byteBuffer.put(remainByte); //将未转换完的字节写入bBuf,与下次读取的byte一起转换

83 }84

85 bytesRead =inChannel.read(byteBuffer);86 }87

88 aFile.close();89 } catch(Exception e) {90 //TODO Auto-generated catch block

91 e.printStackTrace();92 }93 }94

95 private void filewrite() throwsException {96 RandomAccessFile accessFile = new RandomAccessFile("src/com/nio/test/nio-data11.txt", "rw");97 FileChannel fileChannel =accessFile.getChannel();98 String newDate = "New String to write to file" +System.currentTimeMillis();99 ByteBuffer buffer = ByteBuffer.allocate(48);100 buffer.clear();101 buffer.put(newDate.getBytes());102 buffer.flip();103 while(buffer.hasRemaining()) {104 fileChannel.write(buffer);105 }106

107 /**

108 * FileChannel的truncate方法109 * 可以使用FileChannel.truncate()方法截取一个文件。截取文件时,文件将中指定长度后面的部分将被删除。如:110 *111 * 1 channel.truncate(1024); 这个例子截取文件的前1024个字节。112 */

113 //fileChannel.truncate(12);

114 /**

115 * FileChannel.force()方法将通道里尚未写入磁盘的数据制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,116 * 所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。117 */

118 fileChannel.force(true);//force()方法有一个boolean类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上。

119

120 fileChannel.close();121 }122

123 private void clientsocket() throwsException {124 SocketChannel socketChannel =SocketChannel.open();125 //可以设置 SocketChannel 为非阻塞模式(non-blocking mode).设置之后,就可以在异步模式下调用connect(), read() 和write()了。

126 socketChannel.configureBlocking(false);127 socketChannel.connect(new InetSocketAddress("127.0.0.1", 60000));128

129 //为非阻塞模式的判断用

130 while(!socketChannel.finishConnect()){131 socketChannelRead(socketChannel);132 }133 }134

135 /**

136 *137 * ServerSocketChannel138 *139 * Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道,140 * 就像标准IO中的ServerSocket一样。ServerSocketChannel类在 java.nio.channels包中。141 *142 *@throwsException143 *144 */

145 private void serverSocket() throwsException {146 //通过调用 ServerSocketChannel.open() 方法来打开ServerSocketChannel.

147 ServerSocketChannel serverSocketChannel =ServerSocketChannel.open();148 serverSocketChannel.socket().bind(new InetSocketAddress(60000));149 //ServerSocketChannel可以设置成非阻塞模式。在非阻塞模式下,accept()150 //方法会立刻返回,如果还没有新进来的连接,返回的将是null。151 //因此,需要检查返回的SocketChannel是否是null.

152 serverSocketChannel.configureBlocking(false);153 //通常不会仅仅只监听一个连接,在while循环中调用 accept()方法.

154 while (true) {155 //监听新进来的连接156 //通过 ServerSocketChannel.accept() 方法监听新进来的连接。当157 //accept()方法返回的时候,它返回一个包含新进来的连接的 SocketChannel。158 //因此, accept()方法会一直阻塞到有新连接到达。

159 SocketChannel socketChannel =serverSocketChannel.accept();160

161 //非阻塞模式

162 if (socketChannel != null) {163 socketChannelRead(socketChannel);164 }165 //通过调用ServerSocketChannel.close() 方法来关闭ServerSocketChannel166 //serverSocketChannel.close();

167 }168 }169

170 private static StringBuilder socketChannelRead(SocketChannel socketChannel) throwsException {171

172 StringBuilder sb = newStringBuilder();173

174 Charset charset = Charset.forName("GBK");175 CharsetDecoder decoder =charset.newDecoder();176

177 ByteBuffer byteBuffer = ByteBuffer.allocate(10);178 CharBuffer charBuffer = CharBuffer.allocate(10);179

180 int bytesRead =socketChannel.read(byteBuffer);181

182 char[] tmp = null; //临时存放转码后的字符

183 byte[] remainByte = null;//存放decode操作后未处理完的字节。decode仅仅转码尽可能多的字节,此次转码不了的字节需要缓存,下次再转

184 int leftNum = 0; //未转码的字节数

185

186 while (bytesRead != -1) {187

188 //System.out.println("Read " + bytesRead);

189 byteBuffer.flip(); //make buffer ready for read

190 CoderResult result = decoder.decode(byteBuffer, charBuffer, false);191 //System.out.println("result:"+ result);

192 charBuffer.flip();193

194 remainByte = null;195 leftNum = byteBuffer.limit() -byteBuffer.position();196 if (leftNum > 0) { //记录未转换完的字节

197 remainByte = new byte[leftNum];198 byteBuffer.get(remainByte, 0, leftNum);199 }200

201 //输出已转换的字符

202 tmp = new char[charBuffer.length()];203 while(charBuffer.hasRemaining()) {204 charBuffer.get(tmp);205 //sb.append(tmp);

206 System.out.print(newString(tmp));207 }208

209 byteBuffer.clear(); //make buffer ready for writing

210 charBuffer.clear();211

212 if (remainByte != null) {213 byteBuffer.put(remainByte); //将未转换完的字节写入bBuf,与下次读取的byte一起转换

214 }215 bytesRead =socketChannel.read(byteBuffer);216 }217 returnsb;218 }219

220 /**

221 * Java NIO中的DatagramChannel是一个能收发UDP包的通道。222 * 因为UDP是无连接的网络协议,所以不能像其它通道那样读取和写入。它发送和接收的是数据包。223 *224 *@throwsException225 */

226 private void serverDatagram() throwsException {227 /**

228 * 这个例子打开的 DatagramChannel可以在UDP端口9999上接收数据包。229 */

230 DatagramChannel channel =DatagramChannel.open();231 channel.socket().bind(new InetSocketAddress(60000));232

233 Charset charset = Charset.forName("GBK");234 CharsetDecoder decoder =charset.newDecoder();235

236 //通过receive()方法从DatagramChannel接收数据237 //receive()方法会将接收到的数据包内容复制到指定的Buffer.238 //如果Buffer容不下收到的数据,多出的数据将被丢弃。

239 ByteBuffer byteBuffer = ByteBuffer.allocate(48);240 CharBuffer charBuffer = CharBuffer.allocate(48);241 byteBuffer.clear();242 channel.receive(byteBuffer);243

244 char[] tmp = null; //临时存放转码后的字符

245 while(true){246 byteBuffer.flip();247

248 CoderResult result = decoder.decode(byteBuffer, charBuffer, false);249

250 charBuffer.flip();251 tmp = new char[charBuffer.length()];252 while(charBuffer.hasRemaining()) {253 charBuffer.get(tmp);254 System.out.print(newString(tmp));255 }256 byteBuffer.clear();257 charBuffer.clear();258 channel.receive(byteBuffer);259 }260 }261 /**

262 * 可以将DatagramChannel“连接”到网络中的特定地址的。由于UDP是无连接的,263 * 连接到特定地址并不会像TCP通道那样创建一个真正的连接。264 * 而是锁住DatagramChannel ,让其只能从特定地址收发数据。265 * 当连接后,也可以使用read()和write()方法,就像在用传统的通道一样。只是在数据传送方面没有任何保证。266 *267 *@throwsException268 */

269 private void clientDatagram() throwsException {270 DatagramChannel channel =DatagramChannel.open();271 String newData = "New^啊&ng& to write to fasdfsdafsdfdsfsadf1JLKJL)(&)&*(&&ile..." +System.currentTimeMillis();272 ByteBuffer buf = ByteBuffer.allocate(480);273 buf.clear();274 buf.put(newData.getBytes("GBK"));275 buf.flip();276

277 //通过send()方法从DatagramChannel发送数据 即使下面的地址无法连接也是可以发送数据的。

278 int bytesSent = channel.send(buf, new InetSocketAddress("127.0.0.1", 60000));279 //UDP在数据传送方面没有任何保证。

280 }281

282 /**

283 * Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。284 * 数据会被写到sink通道,从source通道读取。285 *@throwsException286 */

287 private void pipe() throwsException {288

289 Pipe pipe =Pipe.open();290

291 //构建一条线程 ,获取管道的SinkChannel,用于数据录入

292 Thread thread = new Thread(() ->{293 //向管道写数据294 //要向管道写数据,需要访问sink通道。295 //通过调用SinkChannel的write()方法,将数据写入SinkChannel,像这样:

296 Pipe.SinkChannel sinkChannel =pipe.sink();297 String newData = "New String to write to file..." +System.currentTimeMillis();298 ByteBuffer buf = ByteBuffer.allocate(48);299 buf.clear();300 try{301 buf.put(newData.getBytes("GBK"));302

303 buf.flip();304 while(buf.hasRemaining()) {305 sinkChannel.write(buf);306 }307 } catch(Exception e) {308 //TODO Auto-generated catch block

309 e.printStackTrace();310 }311 });312

313 //构建一条线程 ,让其去获取到SinkChannel录入的数据并输出

314 Thread thread1 = new Thread(() ->{315 //从管道读取数据316 //从读取管道的数据,需要访问source通道,317 //调用source通道的read()方法来读取数据,

318 Pipe.SourceChannel sourceChannel =pipe.source();319

320 Charset charset = Charset.forName("GBK");321 CharsetDecoder decoder =charset.newDecoder();322

323 ByteBuffer byteBuffer = ByteBuffer.allocate(48);324 CharBuffer charBuffer = CharBuffer.allocate(48);325

326 char[] tmp = null; //临时存放转码后的字符

327 byte[] remainByte = null;//存放decode操作后未处理完的字节。decode仅仅转码尽可能多的字节,此次转码不了的字节需要缓存,下次再转

328 int leftNum = 0; //未转码的字节数329

330 //read()方法返回的int值会告诉我们多少字节被读进了缓冲区。

331 intbytesRead;332 try{333 bytesRead =sourceChannel.read(byteBuffer);334

335 while (bytesRead != -1) {336

337 //System.out.println("Read " + bytesRead);

338 byteBuffer.flip(); //make buffer ready for read

339 CoderResult result = decoder.decode(byteBuffer, charBuffer, false);340 //System.out.println("result:"+ result);

341 charBuffer.flip();342

343 remainByte = null;344 leftNum = byteBuffer.limit() -byteBuffer.position();345 if (leftNum > 0) { //记录未转换完的字节

346 remainByte = new byte[leftNum];347 byteBuffer.get(remainByte, 0, leftNum);348 }349

350 //输出已转换的字符

351 tmp = new char[charBuffer.length()];352 while(charBuffer.hasRemaining()) {353 charBuffer.get(tmp);354 //sb.append(tmp);

355 System.out.print(newString(tmp));356 }357

358 byteBuffer.clear(); //make buffer ready for writing

359 charBuffer.clear();360

361 if (remainByte != null) {362 byteBuffer.put(remainByte); //将未转换完的字节写入bBuf,与下次读取的byte一起转换

363 }364 bytesRead =sourceChannel.read(byteBuffer);365 }366 } catch(IOException e) {367 //TODO Auto-generated catch block

368 e.printStackTrace();369 }370 });371

372 thread.run();373 Thread.sleep(2000L);374 thread1.run();375

376 }377

378 /**

379 * Path接口是java NIO2的一部分。首次在java 7中引入。Path接口在java.nio.file包下,380 * 所以全称是java.nio.file.Path。 java中的Path表示文件系统的路径。可以指向文件或文件夹。381 * 也有相对路径和绝对路径之分。绝对路径表示从文件系统的根路径到文件或是文件夹的路径。382 * 相对路径表示从特定路径下访问指定文件或文件夹的路径。相对路径的概念可能有点迷糊,可以自己百度一下。383 * 不要将文件系统的path和操作系统的环境变量path搞混淆。java.nio.file.Path接口和操作系统的path环境变量没有任何关系。384 * 在很多方面,java.nio.file.Path接口和java.io.File有相似性,但也有一些细微的差别。385 * 在很多情况下,可以用Path来代替File类。386 */

387 private voidNIOPath() {388 //为了使用java.nio.file.Path实例,必须首先创建它。可以使用Paths 类的静态方法Paths.get()来产生一个实例。389 //请注意例子开头的两个import语句。想要使用Paths类和Path接口,必须首先引入相应包。390 //其次,注意Paths.get(“c:\\data\\myfile.txt”)的用法。391 //其使用了Paths.get方法创建了Path的实例。它是一个工厂方法。

392 Path path = Paths.get("c:\\data\\myfile.txt");//绝对路径Path393

394

395 //创建相对路径Path396 //java NIO Path类也能使用相对路径。可以通过Paths.get(basePath, relativePath)创建一个相对路径Path。

397 Path projects = Paths.get("d:\\data", "projects");398 //创建了一个指向d:\data\projects文件夹的实例。

399 Path file = Paths.get("d:\\data", "projects\\a-project\\myfile.txt");400 //创建了一个指向 d:\data\projects\a-project\myfile.txt 文件的实例。401 //.表示当前路径。例如,如果以如下方式创建一个相对路径:402 //创建的Path实例对应的路径就是运行这段代码的项目工程目录。

403 Path currentDir = Paths.get(".");404 System.out.println(currentDir.toAbsolutePath());405 //..表示父类目录。

406 Path parentDir = Paths.get("..");407 String path1 = "d:\\data\\projects\\a-project\\..\\another-project";408 Path parentDir2 =Paths.get(path1);409 //d:\data\projects\another-project在a-project目录后面的..符号,410 //将指向的目录修改为projects目录,因此,最终path指向another-project目录。411

412

413 //Path 的normalize()方法可以标准化路径。

414 String originalPath =

415 "d:\\data\\projects\\a-project\\..\\another-project";416

417 Path path3 =Paths.get(originalPath);418 System.out.println("path3 = " +path3);419

420 Path path2 =path3.normalize();421 System.out.println("path2 = " +path2);422 //如你所见,标准化后的路径不再包含 a-project\..部分,因为它是多余的。423

424 //Files.exists()425 //Files.exists()方法用来检查文件系统中是否存在某路径。426 //Path实例对应的路径可能在文件系统中并不存在。例如,如果打算新建一个文件夹,首先需要创建一个对应的Path实例,然后才能创建对应路径下的文件夹。427 //因为Path实例对应的路径在文件系统的存在性不确定,可以使用Files.exists()方法确认Path对应的路径是否存在 (也就是开发需要自己显式的去调用该方法确认)。428 //如下是Files.exists()的示例:

429 Path path5 = Paths.get("data/logging.properties");430

431 boolean pathExists = Files.exists(path, newLinkOption[] { LinkOption.NOFOLLOW_LINKS });432 System.out.println(pathExists);433 //示例中首先创建了一个Path。然后,通过调用Files.exists方法并将path作为第一个参数确认path对应的路径是否存在。434 //注意下Files.exist()方法的第二个参数。第二个参数数组是评判路径是否存在时使用的规则。435 //示例中,数组包含LinkOption.NOFOLLOW_LINKS枚举类型,表示Files.exists不会跟进到路径中有连接的下层文件目录。436 //表示path路径中如果有连接,Files.exists方法不会跟进到连接中去

437 }438

439 private void byteBufferUtf8() throwsException {440 Charset charset = null;441 CharsetDecoder decoder = null;442 String charsetName = "UTF-8";443 int capacity = 10;444

445 charset =Charset.forName(charsetName);446 decoder =charset.newDecoder();447

448 String s = "客户端发送dsad德生科技电脑fdas上考虑迪士尼年少弗拉门发生ofjam打什么的即破发麦克 ‘;打, 饭哦按asdfasfsdfdfsfdsf都客户端发送dsad德生科技电脑fdas上考虑迪士尼年少弗拉门发生ofjam打什么的即破发麦克 ‘;打, 饭哦按asdfasfsdfdfsfdsf都客户端发送dsad德生科技电脑fdas上考虑迪士尼年少弗拉门发生ofjam打什么的即破发麦克 ‘;打, 饭哦按asdfasfsdfdfsfdsf都客户端发送dsad德生科技电脑fdas上考虑迪士尼年少弗拉门发生ofjam打什么的即破发麦克 ‘;打, 饭哦按asdfasfsdfdfsfdsf都";449 byte[] bytes =s.getBytes(charsetName);450

451 //模拟接收的ByteBuffer size 10

452 ByteBuffer byteBuffer =ByteBuffer.allocate(capacity);453 //用于临时存放Bytebuffer转换后的字符

454 CharBuffer charBuffer =CharBuffer.allocate(capacity);455 //用于连接展示字符串

456 StringBuilder sb = newStringBuilder();457

458 int i = 0;459 while (true) {460 byteBuffer.put(bytes[i]);461 i++;462 if (byteBuffer.remaining() == 0 || i ==bytes.length) {463 byteBuffer.flip();464 CoderResult coderResult;465 if (i !=bytes.length) {466 coderResult = decoder.decode(byteBuffer, charBuffer, false);467 } else{468 coderResult = decoder.decode(byteBuffer, charBuffer, true);469 }470 //有错误

471 if(coderResult.isError()) {472 coderResult.throwException();473 }474 charBuffer.flip();475 sb.append(charBuffer);476 charBuffer.clear();477 byteBuffer.compact();478 }479 //退出循环

480 if (i ==bytes.length) {481 break;482 }483 }484 System.out.println(sb);485 }486 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值