//updating
IO模型有阻塞IO、非阻塞IO、IO复用、信号驱动IO和异步IO,POSIX标准:同步和异步IO。IO:发起IO请求和实际的IO操作,同步IO和异步IO区别于第二步是否阻塞;阻塞IO和非阻塞IO区别于第一步发起IO请求是否会被阻塞,如果阻塞直到完成就是阻塞IO。
读(外存到内存:将数据从网卡到系统空间; 从系统空间到用户空间)输入流,写(将数据从用户空间到系统空间;从系统空间往网卡写)输出流。
字节流( 字符流(文本):流中最小的数据单元是字符, Java中的字符是Unicode编码,按一定编解码方式互转InputStreamReader、OutputStreamWriter ):有序、始、终点的字节序列。
InputStream/Out(二进制格式操作):ByteArray(内存),File(外存),Piped(线程),Buffered,StringBuffer,Filter(可过滤),Object,Data(基本数据类型),; Reader/Writer:CharArray(内存),File,Piped,Buffered,String,Filter;
RandomAccessFile(随机文件操作):可以从文件的任意位置输入输出。SequenceInputStream ( 把多个输入流连接成一个) ,LineNumberReader/ LineNumberInputStream(读时记行),PushbackReader/ PushbackInputStream(缓存实现预读)。
eg.: serverSocket.bind(8088);
while(!Thread.currentThread.isInturrupted())//死循环等待新连接到来
{executor.submit(new ConnectIOThread (serverSocket.accept();//));}
class ConnectIOThread extends Thread{
private Socket socket;
public ConnectIOThread (Socket socket){
this.socket = socket;
}
public void run(){
while(!Thread.currentThread.isInturrupted()&&!socket.isClosed()){//死循环读写
String someThing = socket.read(); //阻塞直到有数据 socket.write();// }
}
}
XML生成:public static void save(List<SomeNode> persons, Writer writer::new OutputStreamWriter(new FileOutputStream(new File(getFilePath() + "/student.xml")), "UTF-8")) throws Throwable{
XmlSerializer serializer = Xml.newSerializer();
BufferedWriter writer2 = new BufferedWriter(writer);//
serializer.setOutput(writer2);
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
serializer.startTag(null, "student");
for(SomeNodeperson : persons){
serializer.startTag(null, "student"); serializer.attribute(null, "id", person.getId().toString()); serializer.attribute(null, "group", person.group);
serializer.startTag(null, "name"); serializer.text(person.getName()); serializer.endTag(null, "name");
serializer.startTag(null, "age"); serializer.text(person.getAge().toString()); serializer.endTag(null, "age");
serializer.endTag(null, "student");
}
serializer.endTag(null, "student");
serializer.endDocument();
writer.flush();
writer.close();
} 解析(基于流操作文件,根据节点回调):public List<SomeNode> pullParseXml(){
List<SomeNode> lists=null;
SomeNode student=null;
try {
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlPullParser pullParser=factory.newPullParser(); //Xml.newPullParser();
InputStream in=this.getClass().getClassLoader().getResourceAsStream("student.xml"); //<?xml version="1.0" encoding="utf-8"?>要顶格显示
pullParser.setInput(in, "UTF-8");
int eventType=pullParser.getEventType();
while(eventType!=XmlPullParser.END_DOCUMENT){
String nodeName=pullParser.getName();
switch (eventType) {
case XmlPullParser.START_DOCUMENT: //文档开始
lists=new ArrayList<SomeNode>(); break;
case XmlPullParser.START_TAG: //开始节点
if("someNode".equals(nodeName)){
student=new SomeNode();
student.setId(pullParser.getAttributeValue(0)); //本节点属性值
student.setGroup(pullParser.getAttributeValue(1));
}else if("name".equals(nodeName)){ // 开始子节点
student.setName(pullParser.nextText());
}else if("age".equals(nodeName)){
student.setAge(pullParser.nextText());
} break;
case XmlPullParser.END_TAG:
if("student".equals(nodeName)){
lists.add(student);
student=null;
} break; default: break;
}
eventType=pullParser.next(); // 手动触发下一个事件
}
} catch (Exception e) { e.printStackTrace(); }
return lists;
}
NIO(IO线程池:NIO并不是严格意义上的非阻塞IO而应该属于多路复用IO):Selector(允许1线程处理多个Channel,打开了多个连接(通道)时但每个连接的流量都不大,如聊天服务器) 基于流,Channel(“流”:UDP/TCP 网络,文件IO:SocketChannel,ServerSocketChannel,FileChannel,DatagramChannel),Buffer (通过IO发送的基本数据类型:ByteBuffer(DirectByteBuffer类似Buffer上的缓存,不是分配在堆上的,它不被GC直接管理,由系统内存进行分配,不被JVM管理(但Direct Buffer的JAVA对象是归GC管理的,只要GC回收了它的JAVA对象,系统才释放Direct Buffer所申请的空间);HeapByteBuffer分配在堆上,byte[]数组。创建和释放DirectByteBuffer的代价比HeapByteBuffer高,因为JVM堆中分配和释放内存比系统高效。把一个Direct Buffer写入一个Channel的速度要比把一HeapByteBuffer写入的快。 一个ByteBuffer经常被重用可考虑DirectByteBuffer对象,如果是需要经常释放和分配的地方用HeapByteBuffer) :CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer,Mappedyteuffer(内存映射文件) )。
通过Buffer (缓冲区内存:capacity,position(写时,表当前位置,position会向前移动到下一个可插入数据的Buffer单元。最大为capacity – 1,初始值为0;读时,position向前移动到下一个可读的位置),limit(写时,表最多能往Buffer里写多少数据,为capacity;读时, 表最多能读到多少数据,会被设置成写时的position值,即能读到之前写入的所有数据) ) 读写,可以从通道中读取数据,又可以写数据到通道,通道可异步读写,但流的读写通常是单向的。buffer.flip()从写模式切换到读,会将position设回0,limit设置成之前position值,position现在用于标记读的位置,limit表示之前写进了多少,现在就能读出多少。
Reactor模式:interface ChannelHandler{
void channelReadable(Channel channel);
void channelWritable(Channel channel);
}
class Channel{
Socket socket;
Event event;//读,写或连接
}
class IoThread extends Thread{//IO线程主循环:
public void run(){
Channel channel;
while(channel=Selector.select()){//选择就绪的事件和对应的连接
if(channel.event==accept){
registerNewChannelHandler(channel);//是新连接则注册新读写器
}
if(channel.event==write){
getChannelHandler(channel).channelWritable(channel);//可以写,则写
}
if(channel.event==read){
getChannelHandler(channel).channelReadable(channel);//可以读,则读
}
}
}
Map<Channel,ChannelHandler> handlerMap;//所有channel的对应事件处理器
}
NIO里何时可以读,比如socket主要的读、写、注册和接收函数,在等待就绪阶段都是非阻塞的,真正的I/O操作是同步阻塞的。AIO模型何时读完了
AIO:
网络: