JDK1.4的java.nio.*包中,引入了新的javaI/O类库,其目的在于提高速度。
速度的提高来自于使用的结构更接近于操作系统执行I/O的方式:通道和缓冲器。
通道要么从缓冲中获得数据,要么向缓冲器发送数据。
唯一直接与通道交互的缓冲器是ByteBuffer-----也就是说,可以存储未加工字节的缓冲器。ByteBuffer是个相当基础的类,通过告知分配多少存储空间来创建一个ByteBuffer对象,并且还有一个方法选择集用于以原始的字节形式或基本数据类型输出和读取数据。但是没办法输出或读取对象,即使是字符串对象也不行。
用新I/O来实现对文本文件的拷贝:
FileChannel in = new FileInputStream("d:\\a.txt").getChannel();
FileChannel out = new FileOutputStream("d:\\b.txt").getChannel();
ByteBuffer bb = ByteBuffer.allocate(1024);
while(in.read(bb)!=-1) {
bb.flip();
out.write(bb);
bb.clear();
}
----------------------------------------------------------------------------------------------------------------------------
在NIOZ中提供了特殊的方法transferTo()和transferFrom(),允许我们将一个通道和另一个通道直接连接:
abstract long
transferFrom(ReadableByteChannel src, long position, long count)
将字节从给定的可读取字节通道传输到此通道的文件中。
abstract long
transferTo(long position, long count,WritableByteChannel target)
将字节从此通道的文件传输到给定的可写入字节通道。
FileChannel in = new FileInputStream("d:\\a.txt").getChannel();
FileChannel out = new FileOutputStream("d:\\b.txt").getChannel();
in.transferTo(0,in.size(),out);
//or ---
//out.transferFrom(in,0,in.size());
--------------------------------------------------------------------------------------------------------------------------------
对输入和输出的文本进行编码和解码
FileChannel out = new FileOutputStream("D:\\a.txt").getChannel();
FileChannel in = new FileInputStream("D:\\a.txt").getChannel(); //两个FileChannel对象关联一个文件,一个负责写,一个读取
out.write(ByteBuffer.wrap("您好".getBytes("GBK"))); //采用GBK编码
out.close();
ByteBuffer buf = ByteBuffer.allocate(1024);
in.read(buf);
buf.flip();
in.close();
System.out.println(Charset.forName("gbk").decode(buf)); //输出时根据GBK解码
缓冲器容纳的是普通的字节,为了把他们转换成字符,我们要么在输入它们的时候对其进行编码(这样,它们的输出才有意义),要么在将其从缓冲器输出时对它们进行解码。
----------------------------------------------------------------------------------------------------------------------------------------------
视图缓冲器
view buffer可以让我们通过某个特定的基本数据类型的视窗查看其底层的ByteBuffer。ByteBuffer依然是实际存储数据的地方,“支持着前面的视图”,因此,对视图的任何修改都会映射成为对ByteBuffer中的数据修改。ByteBuffer中提供了一系列的 " as "方法,用来转换成各种类型的buffer.
ByteBuffer buf = ByteBuffer.allocate(1024);
IntBuffer ib = buf.asIntBuffer();
ib.put(new int[]{1,3,45,32,34,323,122});
System.out.println(ib.get(3));
ib.put(3, 110);
ib.flip();
while (ib.hasRemaining()) {
System.out.print(ib.get() + ",");
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------
字节存放次序
不同的机器可能会使用不同的字节排序方法来存储数据。big endian(高位优先)将最重要的字节存放在地址最低的存储器单元。而 little endian(低位优先)则是将最重要的字节放在地址最高的存储器单元。ByteBuffer是以高位优先的形式存储数据的,并且数据在网上传送时也常常使用高位优先的形式。我们可以使用ByteOrder.BIG_ENDIAN或ByteOrder.LITTLE_ENDIAN的order()方法改变ByteBuffer的字节排序方式。
ByteBuffer buf = ByteBuffer.wrap(new byte[10]);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
buf.rewind();
buf.order(ByteOrder.BIG_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
buf.rewind();
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
~~~~~~~~ByteBuffer有足够的空间,以存储作为外部缓冲器的CharArray中的所有的字节,因此可以调用array()方法显示视图底层的字节。array()方法是可选的,并且我们只能对由数组支持的缓冲器调用此方法,否则,将会抛出UnsupportedOperationException。
通过CharBuffer视图可以将charAarry插入到ByteBuffer中,在底层的字节被显示时,我们会发现默认次序和随后的高位优先次序相同,然而低位优先次序则与之相反,后者交换了这些字节次序。
-----------------------------------------------------------------------------------------------------------------------------------------------------------