Channel
channel是什么
Channel 是一种新的 I/O 的访问方式, 就是可以进行传输数据,传输的数据可以是文件也可以是Socket套接字;
程序不能访问Channel,Channel能与Buffer进行交互,即把通道中的数据传递给Buffer,程序再去访问Buffer;
常用的Channel有
FileChannel, 读写文件的通道
SocketChannel/ ServerSocketChannel, 读写 Socket 套接字中的数据
DatagramChannel, 通过 UDP 读写网络数据
Channel简单介绍
常用的三类方法:
map() 创建一个MappedByteBuffer,它继承ByteBuffer
read() 从Channel中读数据写入缓冲区
write() 将缓冲区中的数据写入到Channel中
FileChannel
使用RandomAccessFile类进行包装File获得的FileChannel可以双向读写
FileInputStream对象的getChannel方法创建FileChannel
inChannel.transferTo(0, file.length(), outChannel);
outChannel.transferFrom(inChannel, 0, file.length()); FileChannel特有方法把 inChannel 从 0 开始的所有字节传输到 outchannel 中
ServerSocketChannel 与 SocketChannel
ServerSocketChannel 可以监听新进来的 TCP 连接通道
SocketChannel 是一个连接到 TCP 网络套接字的通道.
ServerSocketChannel.open(); 创建ServerSocketChannel对象SocketChannel.open(); 创建SocketChannel对象
ssc.socket().bind( new InetSocketAddress(port)); 绑定端口
ssc.configureBlocking(false); 设置为非阻塞
SocketChannel sc = ssc.accept(); 接收请求
DatagramChannel
DatagramChannel可以监听新进来的 UDP 连接通道
Scatter散射/Gather聚集
Scatter
package com.lizhiyu.com;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Test {
public static void main(String[] args) throws IOException {
ByteBuffer byteBuffer=ByteBuffer.allocate(10);
ByteBuffer byteBuffer2=ByteBuffer.allocate(10);
ByteBuffer[] bufferArray={byteBuffer,byteBuffer2};
FileChannel channel=null;
//从channel中读取数据
channel.read(bufferArray);
}
}
Gather
package com.lizhiyu.com;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Test {
public static void main(String[] args) throws IOException {
ByteBuffer byteBuffer=ByteBuffer.allocate(10);
ByteBuffer byteBuffer2=ByteBuffer.allocate(10);
ByteBuffer[] bufferArray={byteBuffer,byteBuffer2};
FileChannel channel=null;
// 将Buffer中的数据写入到Channel中
channel.write(bufferArray);
}
}
FileChannel
MappedByteBuffer的应用
package com.lizhiyu.com;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
public class Test {
public static void main(String[] args) throws IOException {
File file=new File("Test.java");
System.out.println(file.getAbsolutePath());
if(!file.exists()){
file.createNewFile();
}
//使用inputStream只能获得文件中的数据
FileChannel inchannel = new FileInputStream(file).getChannel();
//获得文件只能进行读,因为使用FileInputStream
MappedByteBuffer mappedByteBuffer = inchannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
//使用outputstream可以对文件进行写操作
FileChannel outchannel = new FileOutputStream(new File("Test2.java")).getChannel();
//将缓冲区中的数据写入到Channel中
outchannel.write(mappedByteBuffer);
//也可以把 buf 中的内容打印出来
//切换为读模式
mappedByteBuffer.flip();
//创建字符集
Charset charset = Charset.defaultCharset();
//使用默认字符集把 buf 中的字节转换为字符
CharBuffer decode = charset.decode(mappedByteBuffer);
System.out.println( decode );
inchannel.close();
}
}
使用FileChannel进行文件复制
package com.lizhiyu.com;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Test {
public static void main(String[] args) throws IOException {
File file=new File("F:\\文档\\study\\workspace\\Test\\src\\com\\lizhiyu\\com\\Test.java");
File file2=new File("F:\\文档\\study\\workspace\\Test\\src\\com\\lizhiyu\\com\\Test2.java");
FileChannel inchannel = new FileInputStream(file).getChannel();
FileChannel outchannel = new FileOutputStream(file2).getChannel();
//创建直接字节流缓冲区
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
//这种方法读写数据不可以,因为缓冲区大小是固定的读取不了大量数据
//将channel中的数据写入到Channel中
// inchannel.read(allocateDirect);
// allocateDirect.flip();
// //创建字符集
// Charset charset = Charset.defaultCharset();
// //使用默认字符集把 buf 中的字节转换为字符
// CharBuffer decode = charset.decode(allocateDirect);
// System.out.println(decode);
//从 ihChannel 中读取数据保存到 buf 中
int readBytes = inchannel.read(buf);
//当 readBytes 不为-1 时,没有读取到文件末尾
while( readBytes != -1 ){
//把 buf 中的内容写到 outChannel 中
buf.flip(); //切换为坊模式
outchannel.write(buf);
buf.clear();
readBytes = inchannel.read(buf);
}
inchannel.close();
outchannel.close();
}
}
使用RandomAccessFile可以读可以写
package com.lizhiyu.com;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("F:\\文档\\study\\workspace\\Test\\src\\com\\lizhiyu\\com\\Test.java");
File file2 = new File("F:\\文档\\study\\workspace\\Test\\src\\com\\lizhiyu\\com\\Test2.java");
FileChannel fileChannel = new RandomAccessFile(file,"rw").getChannel();
FileChannel fileChannel2=new FileOutputStream(file2).getChannel();
MappedByteBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
//将缓冲区中的数据写入到channel中
fileChannel2.write(map);
}
}
使用FileChannel的特有方法
package com.lizhiyu.com;
import java.io.File;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
public class Test {
//一般使用这个方法相对速度较快
public static void main(String[] args) {
//把 out.txt 文件复制到 out3.txt 中
File file = new File("out.txt");
try(
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileChannel inChannel = raf.getChannel();
FileChannel outChannel = new FileOutputStream("out3.txt").getChannel();
) {
//把 inChannel从 0 开始的所有字节传输到 outchannel中
// inChannel.transferTo(0, file.length(), outChannel);
outChannel.transferFrom(inChannel, 0, file.length());
} catch (Exception e) {
}
}
}
将多个缓冲区的数据写入到文件中Gather
package com.lizhiyu.com;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Test {
public static void main(String[] args) throws IOException {
ByteBuffer byteBuffer=ByteBuffer.allocate(1000);
byteBuffer.put("第一个缓冲区".getBytes());
byteBuffer.flip();
ByteBuffer byteBuffer2=ByteBuffer.allocate(1000);
byteBuffer2.put("第二个缓冲区".getBytes());
byteBuffer2.flip();
File file=new File("F:\\文档\\study\\workspace\\Test\\src\\com\\lizhiyu\\com\\Test2.java");
FileChannel fileChannel=new FileOutputStream(file).getChannel();
ByteBuffer[] bytebufferArray={byteBuffer,byteBuffer2};
//将多个buffer写入到channel中
fileChannel.write(bytebufferArray);
}
}
ServerSocketChannel 与 SocketChannel
Server
package com.lizhiyu.com;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.bind(new InetSocketAddress(8888));
//设置成为阻塞
ssc.configureBlocking(true);
while(true){
SocketChannel sc = ssc.accept();
//先给客户端发送一个问候
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("hello, I am from socketServer".getBytes());
buffer.flip();
sc.write(buffer);
//再读取客户端中发送来的内容
System.out.println("from Sockte Client : " + sc.socket().getRemoteSocketAddress());
buffer.clear();
sc.read(buffer); //读取客户端发送的数据保存到 buffer 中
buffer.flip();
CharBuffer decode = Charset.defaultCharset().decode(buffer);
System.out.println( decode );
}
}
}
Client
package com.lizhiyu.com;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
public class Client {
public static void main(String[] args) throws IOException {
SocketChannel sc = SocketChannel.open();
boolean connect = sc.connect(new InetSocketAddress(8888));
//向服务器发送消息
ByteBuffer buffer = ByteBuffer.wrap("hello, I am from client socket".getBytes());
while( buffer.hasRemaining()){
sc.write(buffer);
}
//获得服务器发送给客户端的消息
InputStream inputStream = sc.socket().getInputStream();
ReadableByteChannel newChannel = Channels.newChannel(inputStream);
buffer.clear();
newChannel.read(buffer);
buffer.flip();
CharBuffer decode = Charset.defaultCharset().decode(buffer);
System.out.println(decode);
sc.close();
}
}