@huangyichun
2017-08-30T15:56:22.000000Z
字数 7503
阅读 923
I/O
原来I/O是单向的,面向流的
NIO是双向的
import org.junit.Test;
import java.nio.ByteBuffer;
/**
* 一、 缓冲区(buffer):在Java NIO中负责数据的存取,缓冲区就是数组,用于存储不同数据类型的数据
*
* 根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述缓存区的管理几乎一致,通过allocate()获取缓冲区
*
* 二、缓存区存取数据的两个核心方法
* put():存入数据到缓冲区中
* get(): 获取缓冲区中的数据
*
* 三、缓冲区中的四个核心属性
*
* private int mark = -1;标记:表示记录当前position的位置。可以通过reset()恢复mark位置
* private int position = 0; 位置:表示缓冲区中正在操作数据的位置
* private int limit; 界限:表示缓存区中可以操作数据的大小(limit)后面的数据不能进行读写
* private int capacity; 容量:表示缓存区中最大存储数据容量,一旦声明不能改变
*
* 0 <= mark <= position <= limit <= capacity
*
* 四、直接缓冲区与非直接缓冲区
* 非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中
* 直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率
*/
public class TestBuffer {
@Test
public void test3(){
//直接缓冲区
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
System.out.println(buf.isDirect());
}
@Test
public void test2(){
String str = "abcde";
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(str.getBytes());
buf.flip();
byte[] dst = new byte[buf.limit()];
buf.get(dst, 0 ,2);//读取两个
System.out.println(new String(dst,0,2));
System.out.println("position: "+buf.position());
//mark()标记
buf.mark();
buf.get(dst, 2, 2);
System.out.println(new String(dst, 0, 4));
System.out.println("position: "+buf.position());
buf.reset();
System.out.println("position: "+buf.position());
if(buf.hasRemaining()){//判断缓冲区是否还有剩余的
System.out.println(buf.remaining());
}
}
@Test
public void test1() {
String str = "abcde";
//1.分配一个指定大小的缓存区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("------------allocate----------------");
System.out.println("position: "+buf.position());
System.out.println("limit: " + buf.limit());
System.out.println("capacity: " + buf.capacity());
System.out.println("----------------put()------------");
//2.利用put()方法存入数据到缓冲区中——写数据模式
buf.put(str.getBytes());
System.out.println("position: "+buf.position());
System.out.println("limit: " + buf.limit());
System.out.println("capacity: " + buf.capacity());
System.out.println("----------------flip()------------");
//3.切换成读取数据模式
buf.flip();
System.out.println("position: "+buf.position());
System.out.println("limit: " + buf.limit());
System.out.println("capacity: " + buf.capacity());
System.out.println("----------------get()------------");
//4利用get()方法读取缓冲区的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println(new String(dst, 0, dst.length));
System.out.println("position: "+buf.position());
System.out.println("limit: " + buf.limit());
System.out.println("capacity: " + buf.capacity());
System.out.println("----------------rewind()------------");
//5.rewind() 可重复读数据
buf.rewind();
System.out.println("position: "+buf.position());
System.out.println("limit: " + buf.limit());
System.out.println("capacity: " + buf.capacity());
System.out.println("----------------clear()------------");
//6.clear():清空缓冲区,但是缓冲区中的数据依然存在,但是出于"被遗忘"状态
buf.clear();
System.out.println("position: "+buf.position());
System.out.println("limit: " + buf.limit());
System.out.println("capacity: " + buf.capacity());
System.out.println((char)buf.get(1));
}
}
import org.junit.Test;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Stream;
/**
* 一、通道(Channel):用于源节点与目标节点的链接。在Java NIO中负责缓冲区中数据的传输
* Channel本身不存储数据,因此需要配合缓冲区进行传输。
* <p>
* 二、通道的主要实现类
* java.nio.channels.Channel接口:
* |--FileChannel
* |--SocketChannel
* |--ServerSocketChannel
* |--DatagramChannel
* 三、获取通道
* 1. Java支持通道的类提供了getChannel()方法
* 本地IO:
* FileInputStream/FileOutputStream
* RandomAccessFile
* <p>
* 网络IO:
* Socket
* ServerSocket
* DatagramSocket
* 2. 在JDK 1.7中的NIO.2针对各个通道提供了静态方法open()
* 3. 在JDK 1.7中的NIO.2的Files工具类的newByteChannel()
*
* 四、通道之间的数据传输
* transferFrom()
* transferTo()
*
* 五、分散(Scatter)与聚集(Gather)
* 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
* 聚集写入(Gathering Writers):将多个缓冲区中的数据聚集到通道中
*
* 六、字符集:Charset
* 编码: 字符串——>字节数组
* 解码: 字节数组——>字符串
*
*/
public class TestChannel {
//字符集
@Test
public void test7() throws CharacterCodingException {
Charset cs1 = Charset.forName("GBK");
//获取编码器
CharsetEncoder ce = cs1.newEncoder();
//获取解码器
CharsetDecoder cd = cs1.newDecoder();
CharBuffer cBuf = CharBuffer.allocate(1024);
cBuf.put("尚硅谷威武!");
cBuf.flip();//切换读
//编码
ByteBuffer byteBuffer = ce.encode(cBuf);
for(int i=0; i<cBuf.limit()*2; i++){
System.out.println(byteBuffer.get());
}
//解码
byteBuffer.flip();
CharBuffer cBuf2 = cd.decode(byteBuffer);
System.out.println(cBuf2.toString());
}
@Test
public void test6(){
Map<String, Charset> map = Charset.availableCharsets();
map.forEach((x,y)->{
System.out.println(x+"="+y);
});
}
//分散和聚集
@Test
public void test5() throws IOException {
RandomAccessFile raf = new RandomAccessFile("学习清单.txt","rw");
//1.获取通道
FileChannel channel = raf.getChannel();
//2.分配指定大小的缓冲区
ByteBuffer buf1 = ByteBuffer.allocate(100);
ByteBuffer buf2 = ByteBuffer.allocate(1024);
//3.分散读取
ByteBuffer[] bufs = {buf1, buf2};
channel.read(bufs);
Arrays.stream(bufs).forEach(ByteBuffer::flip);//转换成读模式
System.out.println(new String(bufs[0].array(),0, bufs[0].limit()));
System.out.println("------------------------");
System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));
//4.聚集写入
RandomAccessFile raf2 = new RandomAccessFile("2.txt","rw");
FileChannel channel2 = raf2.getChannel();
channel2.write(bufs);
channel.close();
channel2.close();
}
//通道之间的数据传输(直接缓冲区,内存映射文件)
@Test
public void test4() throws IOException {
FileChannel inChannel = FileChannel.open(Paths.get("E:/1.zip"),StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("E:/2.zip"),StandardOpenOption.READ, StandardOpenOption.WRITE,StandardOpenOption.CREATE);
// inChannel.transferTo(0, inChannel.size(), outChannel);
outChannel.transferFrom(inChannel, 0, inChannel.size());
inChannel.close();
outChannel.close();
}
//3. I/O操作
@Test
public void test3() throws IOException { //9755
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("E:/1.zip");
FileOutputStream fos = new FileOutputStream("E:/2.zip");
BufferedInputStream bufis = new BufferedInputStream(fis);
byte[] bts = new byte[1024];
while(bufis.read(bts) != -1){
fos.write(bts);
}
bufis.close();
fis.close();
fos.close();
long end = System.currentTimeMillis();
System.out.println("耗费时间为:" + (end-start));
}
//2.使用直接缓冲区完成文件复制(内存映射文件)
@Test
public void test2() throws IOException {//2457
long start = System.currentTimeMillis();
FileChannel inChannel = FileChannel.open(Paths.get("E:/1.zip"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("E:/2.zip"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
//内存映射文件
MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
//直接对缓冲区对数据的读写操作
byte[] dst = new byte[inMappedBuf.limit()];
inMappedBuf.get(dst);
outMappedBuf.put(dst);
inChannel.close();
outChannel.close();
long end = System.currentTimeMillis();
System.out.println("耗费时间为:" + (end-start));
}
//1.利用通道完成文件的复制(非直接缓冲区)
@Test
public void test1() throws IOException {//9942
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("E:/1.zip");
FileOutputStream fos = new FileOutputStream("E:/2.zip");
//获取通道
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
//分配指定大小的缓存区
ByteBuffer buf = ByteBuffer.allocate(1024);
//将通道中的数据存入缓冲区中
while (inChannel.read(buf) != -1) {
//将缓冲区中的数据写入通道中
buf.flip(); //切换成读取数据的模式
outChannel.write(buf);
buf.clear();//清空缓冲区
}
outChannel.close();
inChannel.close();
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println("耗费时间为:" + (end-start));
}
}