1、voidioRead(Stringfile)throwsIOException 7. FileInputStreamin=newFileInputStream(file);8. bytebbyte1024;9. in.read(b);10. System.out.println(newString(b);11. 12. 13. /* 14. 使用NIO读取指定文件的前1024个字节的内容。15. 16. 17. 18. publicnioRead(String19. 20. FileChannelchannelin.getChannel();21. 22. ByteBufferbufferBy
2、teBuffer.allocate(1024);23. channel.read(buffer);24. buffer.array();25. 26. /* * 使用IO读取指定文件的前1024个字节的内容。 * param file 指定文件名称。 * throws java.io.IOException IO异常。 */public void ioRead(String file) throws IOException FileInputStream in = new FileInputStream(file); byte b = new byte1024; in.read(b); Sys
3、tem.out.println(new String(b); * 使用NIO读取指定文件的前1024个字节的内容。public void nioRead(String file) throws IOException FileChannel channel = in.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); channel.read(buffer); byte b = buffer.array(); 从上面的例子中可以看出,NIO以通道Channel和缓冲区Buffer为基础来实现面向块的IO数据处理。下面将讨论并
4、学习NIO 库的核心概念以及从高级的特性到底层编程细节的几乎所有方面。3.核心概念:通道和缓冲区 1)概述: 通道和缓冲区是NIO中的核心对象,几乎在每一个I/O操作中都要使用它们。 通道Channel是对原I/O包中的流的模拟。到任何目的地(或来自任何地方)的所有数据都必须通过一个Channel对象。 缓冲区Buffer实质上是一个容器对象。发送给一个通道的所有对象都必须首先放到缓冲区中;同样地,从通道中读取的任何数据都要读到缓冲区中。 2)缓冲区: Buffer是一个容器对象,它包含一些要写入或者刚读出的数据。在NIO中加入Buffer对象,体现了新库与原I/O的一个重要区别。在面向流的I
5、/O中,您将数据直接写入或者将数据直接读到Stream对象中。 在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问NIO中的数据,您都是将它放到缓冲区中。 缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。 最常用的缓冲区类型是ByteBuffer。 一个ByteBuffer可以在其底层字节数组上进行get/set操作(即字节的获取和设置)。 ByteBuffer不是NIO中唯一的缓冲区类型。事实
6、上,对于每一种基本Java类型都有一种缓冲区类型: ByteBuffer CharBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer 每一个Buffer类都是Buffer接口的一个实例。 除了ByteBuffer, 每一个Buffer类都有完全一样的操作,只是它们所处理的数据类型不一样。因为大多数标准I/O操作都使用ByteBuffer,所以它具有所有共享的缓冲区操作以及一些特有的操作。 下面的UseFloatBuffer列举了使用类型化的缓冲区FloatBuffer的一个应用例子:使用float缓冲区。versio
7、n1.002010-5-19,10:30:59 since1.5 authorZhangShixi 6. 7. publicclassUseFloatBufferpublicstaticmain(Stringargs)/分配一个容量为10的新的缓冲区 11. FloatBufferFloatBuffer.allocate(10);for(inti0;buffer.capacity();i+)13. f(float)Math.sin(float)i)/10)(2Math.PI);buffer.put(f); 反转此缓冲区 buffer.flip();18. 告知在当前位置和限制之间是否有元素 w
8、hile(buffer.hasRemaining()buffer.get();System.out.println(f);25. * 使用 float 缓冲区。 * version 1.00 2010-5-19, 10:59 * since 1.5 * author ZhangShixipublic class UseFloatBuffer public static void main(String args) / 分配一个容量为10的新的 float 缓冲区 FloatBuffer buffer = FloatBuffer.allocate(10); for (int i = 0; i b
9、uffer.capacity(); i+) float f = (float) Math.sin(float) i) / 10) * (2 * Math.PI); buffer.put(f); / 反转此缓冲区 buffer.flip(); / 告知在当前位置和限制之间是否有元素 while (buffer.hasRemaining() float f = buffer.get(); System.out.println(f); 3)通道: Channel是对原I/O包中的流的模拟,可以通过它读取和写入数据。拿NIO与原来的I/O做个比较,通道就像是流。 正如前面提到的,所有数据都通过Buff
10、er对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节,而是将数据从通道 读入缓冲区,再从缓冲区获取这个字节。通道与流的不同之处在于通道是双向的。而流只是在一个方向上移动(一个流必须是InputStream或者OutputStream的子类), 而通道可以用于读、写或者同时用于读写。 因为它们是双向的,所以通道可以比流更好地反映底层操作系统的真实情况。特别是在UNIX模型中,底层操作系统通道是双向的。4.从理论到实践:NIO中的读和写 读和写是I/O的基本过程。从一个通道中读取很简单:只需创建一个缓冲区,然后让通道将数
11、据读到这个缓冲区中。写入也相当简单:创建一个缓冲区,用数据填充它,然后让通 道用这些数据来执行写入操作。从文件中读取:如果使用原来的I/O,那么我们只需创建一个FileInputStream并从它那里读取。而在NIO中,情况稍有不同:我们首先从FileInputStream获取一个FileChannel对象,然后使用这个通道来读取数据。 在NIO系统中,任何时候执行一个读操作,您都是从通道中读取,但是您不是直接从通道读取。因为所有数据最终都驻留在缓冲区中,所以您是从通道读到缓冲区中。 因此读取文件涉及三个步骤: (1) 从FileInputStream获取Channel。 (2) 创建Buff
12、er。 (3) 将数据从Channel读到Buffer 中。 现在,让我们看一下这个过程。1. /第一步是获取通道。我们从获取通道:2. FileInputStreamfinFileInputStream(readandshow.txt);3. FileChannelfcfin.getChannel();4. /下一步是创建缓冲区:5. ByteBufferByteBuffer.allocate(10246. /最后,需要将数据从通道读到缓冲区中:7. fc.read(/ 第一步是获取通道。我们从 FileInputStream 获取通道:FileInputStream fin = new F
13、ileInputStream( );FileChannel fc = fin.getChannel();/ 下一步是创建缓冲区:ByteBuffer buffer = ByteBuffer.allocate( 1024 );/ 最后,需要将数据从通道读到缓冲区中:fc.read( buffer ); 您会注意到,我们不需要告诉通道要读多少数据到缓冲区中。每一个缓冲区都有复杂的内部统计机制,它会跟踪已经读了多少数据以及还有多少空间可以容纳更多的数据。我们将在缓冲区内部细节中介绍更多关于缓冲区统计机制的内容。写入文件: 在 NIO 中写入文件类似于从文件中读取。首先从FileOutputStrea
14、m获取一个通道:2. FileOutputStreamfoutFileOutputStream(writesomebytes.txtfout.getChannel();下一步是创建一个缓冲区并在其中放入一些数据,这里,用message来表示一个持有数据的数组。6. fori=0;imessage.length;+i)buffer.put(messagei8. 9. buffer.flip();10. /最后一步是写入缓冲区中:11. fc.write(/ 首先从 FileOutputStream 获取一个通道:FileOutputStream fout = new FileOutputStre
15、am( FileChannel fc = fout.getChannel();/ 下一步是创建一个缓冲区并在其中放入一些数据,这里,用message来表示一个持有数据的数组。for (int i=0; i +i) buffer.put( messagei );/ 最后一步是写入缓冲区中:fc.write( buffer ); 注意在这里同样不需要告诉通道要写入多数据。缓冲区的内部统计机制会跟踪它包含多少数据以及还有多少数据要写入。 4)读写结合: 下面的示例将展示使用读写结合,将一个文件的所有内容拷贝到另一个文件中。将一个文件的所有内容拷贝到另一个文件中。CopyFile.java执行三个基本
16、操作:首先创建一个Buffer,然后从源文件中将数据读到这个缓冲区中,然后将缓冲区写入目标文件。程序不断重复读、写、读、写直到源文件结束。49:46 12. publicCopyFileExceptionStringinfileC:copy.sql;outfilecopy.txt获取源文件和目标文件的输入输出流 FileInputStream(infile);FileOutputStream(outfile);获取输入输出通道 fcinfcout26. 创建缓冲区 27. 28. 29. (true)30. clear方法重设缓冲区,使它可以接受读入的数据 31. buffer.clear()
17、;32. 33. 从输入通道中将数据读到缓冲区 34. intrfcin.read(buffer);35. 36. read方法返回读取的字节数,可能为零,如果该通道已到达流的末尾,则返回-1 37. if(r=-1)38. break;39. 40. 41. flip方法让缓冲区可以将新读入的数据写入另一个通道 42. 43. 44. 从输出通道中将数据写入缓冲区 45. fcout.write(buffer);46. 47. 48. * 将一个文件的所有内容拷贝到另一个文件中。 * * CopyFile.java 执行三个基本操作: * 首先创建一个 Buffer,然后从源文件中将数据读到
18、这个缓冲区中,然后将缓冲区写入目标文件。 * 程序不断重复 读、写、读、写 直到源文件结束。46public class CopyFile public static void main(String args) throws Exception String infile = String outfile = / 获取源文件和目标文件的输入输出流 FileInputStream fin = new FileInputStream(infile); FileOutputStream fout = new FileOutputStream(outfile); / 获取输入输出通道 FileCha
19、nnel fcin = fin.getChannel(); FileChannel fcout = fout.getChannel(); / 创建缓冲区 while (true) / clear方法重设缓冲区,使它可以接受读入的数据 buffer.clear(); / 从输入通道中将数据读到缓冲区 int r = fcin.read(buffer); / read方法返回读取的字节数,可能为零,如果该通道已到达流的末尾,则返回-1 if (r = -1) break; / flip方法让缓冲区可以将新读入的数据写入另一个通道 / 从输出通道中将数据写入缓冲区 fcout.write(buffe
20、r);后续: 在下一篇文章中,会具体介绍缓冲区Buffer的内部实现机制,以理解缓冲区如何能够内部地管理自己的资源。有兴趣的可以共同学习、讨论。缓冲区内部实现机制接上一篇NIO学习系列:核心概念及基本读写 ,本文继续探讨和学习缓冲区的内部实现机制。5. 缓冲区内部实现 从上面对NIO的学习中,我们知道每一个缓冲区都有复杂的内部统计机制,它会跟踪已经读了多少数据以及还有多少空间可以容纳更多的数据,以便我们对缓冲区的操作。在本节我们就将学习NIO的两个重要的缓冲区组件:状态变量和访问方法。虽然NIO的内部统计机制初看起来可能很复杂,但是您很快就会看到大部分的实际工作都已经替您完成了。您只需像平时使用字节数组和索引变量一样进行操作即可。 状态变量: 状态变量是前一节中提到的内部统计机制的关键。 每一个读/写操作都会改变缓冲区的状态。通过记录和跟踪这些变化,缓冲区就可能够内部地管理自己的资源。 每一种Java基本类型的缓
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1