一.Channel
- 通道是用于字节缓冲区和位于通道另一边的数据实体之间执行传输数据。
- NIO主要分为File IO和Steam IO,对应通道分为Filechannel和SocketChannel(Socketchannel、ServerSocketChannel和DatagramChannel)。File IO没有非阻塞模式。
- 通道可以多种方式创建,SocketChannel提供直接创建Socket通道的工厂方法(SocketChannel.open),FileChannel只能通过一个打开的RandomAccessFile、FileInputSteam或者FileOutputSteam对象调用getChannel方法获取,不可以直接创建。
- 本文主要讨论Filechannel,非阻塞通信在下节总结
二.Filechannel
- 层次图
- 顶层Channel接口提供了isOpen方法判断通道是否打开和close方法关闭一个打开的通道,InterruptibleChannel是一个标志接口,当通道使用时可以标志该通道可以被中断的。WritableByteChannel和ReadableByteChannel表明通道只能字节缓冲区上操作。Scatter和Gather表示可以在多个缓冲区上执行IO操作。
-
FilechannelImlp是其重要子类
- API
1.map(MapMode mode, long position, long size):可以在一个打开的文件和一个特殊类型的ByteBuffer之间建立一个虚拟内存映射(返回一个MappedByteBuffer对象)。get方法会从磁盘文件中获取文件当前的数据内容,如果建立映射之后文件被其他进程修改,对该进程也是可见的。put方法会更新磁盘上的文件,对文件的修改对其他进程也是可见的。
2.read/write(ByteBuffer var1):从Buffe读数据,从源码中可看出读写是锁了整个线程
public int read(ByteBuffer var1) throws IOException {
Object var2 = this.positionLock;
synchronized(this.positionLock) {
........
var3 = IOUtil.read(this.fd, var1, -1L, this.nd);
........
} finally {
.......
}
}
}
}
三.实例
- read(new FileReader("a.txt")):NIO
readByStream(new File("a.txt")):传统IO
readByMap(new File("a.txt")):内存映射
package IO;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
/**
* Created by admin on 2017/9/21.
*/
public class Stream {
public static void main(String[] args) throws IOException {
read(new FileReader("a.txt"));
readByStream(new File("a.txt"));
readByMap(new File("a.txt"));
new Thread(new Runnable() {
@Override
public void run() {
readByNio(new File("a.txt"), 2);
}
}).start();
}
private static void readByStream(File file) {
BufferedInputStream bs = null;
BufferedOutputStream fs = null;
try {
bs = new BufferedInputStream(new FileInputStream(file));
fs = new BufferedOutputStream(new FileOutputStream(new File("c.txt")));
byte[] b = new byte[1024];
while (bs.read(b) != -1) {
fs.write(b);
fs.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流,其实关闭的就是java调用的系统底层资源。在关闭前,会先刷新该流。
if (fs != null && fs != null) {
Integer a = 1;
try {
bs.close();
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void read(FileReader file) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(file);
//如果d文件中有数据,true表示继续往文件中追加数据
bw = new BufferedWriter(new FileWriter("d.txt", false));
String line = null;
//高效字符输入流的特有方法readline(),每次读取一行数据
while ((line = br.readLine()) != null) {
bw.write(line);
//高效字符输出流的特有方法newline()
bw.newLine();
//将缓冲区中的数据刷到目的地文件中
bw.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭流,其实关闭的就是java调用的系统底层资源。在关闭前,会先刷新该流。
if (bw != null && br != null) {
try {
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void readByNio(File file, Integer type) {
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
FileChannel channel = null;
FileChannel channel1 = null;
String name = "";
if (type == 1) {
name = "b.txt";
} else {
name = "c.txt";
}
try {
fileInputStream = new FileInputStream(file);
fileOutputStream = new FileOutputStream(new File(name));
channel1 = fileOutputStream.getChannel();
channel = fileInputStream.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int read = channel.read(buf);
while (read != -1) {
buf.flip();
while (buf.hasRemaining()) {
channel1.write(buf);
}
buf.compact();
read = channel.read(buf);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (channel != null) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (channel1 != null) {
try {
channel1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void readByMap(File file) {
FileChannel a = null;
FileChannel b=null;
try {
a = new RandomAccessFile("a.txt", "rw").getChannel();
b = new RandomAccessFile("e.txt", "rw").getChannel();
MappedByteBuffer in = a.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
MappedByteBuffer out = b.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
out.put(in);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (a!=null){
a.close();
}
if (b!=null){
a.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}