企业网站建设总结,文具网站建设策划书,做空机构的网站,青岛市建设工程信息网官网BIO是阻塞I/O#xff0c;NIO是非阻塞I/O#xff0c;AIO是异步I/O。BIO每个连接对应一个线程#xff0c;NIO多个连接共享少量线程#xff0c;AIO允许应用程序异步地处理多个操作。NIO#xff0c;通过Selector#xff0c;只需要一个线程便可以管理多个客户端连接#xff0…BIO是阻塞I/ONIO是非阻塞I/OAIO是异步I/O。BIO每个连接对应一个线程NIO多个连接共享少量线程AIO允许应用程序异步地处理多个操作。NIO通过Selector只需要一个线程便可以管理多个客户端连接当客户端数据到了之后才会为其服务AIO是适合高吞吐量的应用程序异步 IO 基于时间和回调机制实现的也就是应用操作之后会直接返回不会阻塞在那里后台处理完成后操作系统会通知相应的线程进行后续的操作。但AIO在Java中的支持相对有限不是所有操作系统都支持。
JAVA BIO 服务端会有个ServerSocket每一个ServerSocket都有一个与之对应ClientSocket每一个连接都需要有一个线程来维护
JAVA NIO
1.Java NIO 全称 Java non-blocking IO是指 JDK 提供的新 API。从 JDK1.4 开始Java 提供了一系列改进的输入/输出的新特性被统称为 NIO(即 NewIO)是同步非阻塞的。
Java NIO 的非阻塞模式使一个线程从某通道发送请求或者读取数据但是它仅能得到目前可用的数据如果目前没有数据可用时就什么都不会获取而不是保持线程阻塞所以直至数据变的可以读取之前该线程可以继续做其他的事情。非阻塞写也是如此一个线程请求写入一些数据到某通道但不需要等待它完全写入这个线程同时可以去做别的事情。 ByteBuffer
缓冲区(ByteBuffer)缓冲区本质上是一个可以读写数据的内存块可以理解成是一个容器对象(含数组)该对象提供了一组方法可以更轻松地使用内存块缓冲区对象内置了一些机制能够跟踪和记录缓冲区的状态变化情况。ByteBuffer的指针有postion Channel
NIO 的通道类似于流主要的区别是通道可以同时进行读写而流只能读或者只能写。通道可以实现异步读写数据。通道可以从缓冲读数据也可以写数据到缓冲。BIO的流是单向的NIO的通道是双向的可以读也可以写操作。
Selector
Java 的 NIO用非阻塞的 IO 方式。可以用一个线程处理多个的客户端连接就会使用到 Selector(选择器)。Selector 能够检测多个注册的通道上是否有事件发生(注意多个 Channel 以事件的方式可以注册到同一个 Selector)如果有事件发生便获取事件然后针对每个事件进行相应的处理。
这样就可以只用一个单线程去管理多个通道也就是管理多个连接和请求。只有在连接/通道真正有读写事件发生时才会进行读写就大大地减少了系统开销并且不必为每个连接都创建一个线程不用去维护多个线程。避免了多线程之间的上下文切换导致的开销。
流
流不能通过索引读写数据流中的数据只能顺序读取
// 将流整合起来以便实现更高级的输入和输出操作。如可以把InputStream包装到BufferedInputStream中以实现缓冲即从磁盘中一次读取一大块数据
InputStream input new BufferedInputStream(new FileInputStream(c:\data\input-file.txt));
OutputStream output new BufferedOutputStream(new FileOutputStream(c:\data\output-file.txt));Java的IO流共涉及40多个类实际上非常规则都是从以上4个抽象基类派生的 java.io.InputStream int read()从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节则返回值 -1。
int read(byte[] b)从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。如果因为已经到达流末尾而没有可用的字节则返回值 -1。否则以整数形式返回实际读取的字节数。
int read(byte[] b, int off, int len)将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节但读取的字节也可能小于该值。java.io.OutputStream void write(int b)
将指定的字节写入此输出流。write 的常规协定是向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 即写入0~255范围的。
void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b,int off,int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
public void flush()throws IOException
刷新此输出流并强制写出所有缓冲的输出字节调用此方法指示应将这些字节立即写入它们预期的目标。java.io.Reader int read()读取单个字符。作为整数读取的字符范围在 0 到 65535 之间 (0x00-0xffff)2个字节的Unicode码如果已到达流的末尾则返回 -1
int read(char[] cbuf)将字符读入数组。如果已到达流的末尾则返回 -1。否则返回本次读取的字符数。
int read(char[] cbuf,int off,int len)将字符读入数组的某一部分。存到数组cbuf中从off处开始存储最多读len个字符。如果已到达流的末尾则返回 -1。否则返回本次读取的字符数。java.io.Writer void write(int c)
写入单个字符。要写入的字符包含在给定整数值的 16 个低位中16 高位被忽略。 即写入0 到 65535 之间的Unicode码。
void write(char[] cbuf)
写入字符数组。
void write(char[] cbuf,int off,int len)
写入字符数组的某一部分。从off开始写入len个字符
void write(String str)
写入字符串。
void write(String str,int off,int len)
写入字符串的某一部分。
void flush()
刷新该流的缓冲则立即将它们写入预期目标JavaIO 文件
用来将文件转换为二进制字节流或字符流
FileInputStream二进制型数据按顺序地读取文件中的字节每次读取一个字节FileReader字符型数据按顺序地读取文件中的字符每次读取一个字符FileOutputStream二进制型数据每次写入一个字节数据按照写入顺序存储在文件当中FileWriter字符型数据每次写入一个字符数据按照写入顺序存储在文件当中
//二进制流范例打开一个文件的输入流读取到字节数组再写入另一个文件的输出流
public void test1() {try {FileInputStream fileInputStream new FileInputStream(new File(a.txt));FileOutputStream fileOutputStream new FileOutputStream(new File(b.txt));byte []buffer new byte[128];while (fileInputStream.read(buffer) ! -1) {fileOutputStream.write(buffer);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
}// 字符流范例
public static void main(String[] args) throws IOException {FileReader fileReader new FileReader(file.txt);FileWriter fileWriter new FileWriter(file2.txt);//一次拷贝4个字节char[] chars new char[1024*1024];int read;while ((read fileReader.read(chars)) ! -1) {fileWriter.write(chars, 0, read);}fileWriter.flush();if (fileReader ! null) {fileReader.close();}if (fileWriter ! null) {fileWriter.close();}}JavaIO管道
Java IO中的管道为运行在同一个JVM中的两个线程提供通信的能力所以管道也可以作为数据源以及目标媒介。不同的JVM中线程不能利用管道进行通信
//使用管道来完成两个线程间的数据点对点传递
Test
public void test2() throws IOException {PipedInputStream pipedInputStream new PipedInputStream();PipedOutputStream pipedOutputStream new PipedOutputStream(pipedInputStream);new Thread(new Runnable() {Overridepublic void run() {try {pipedOutputStream.write(hello input.getBytes());pipedOutputStream.close();} catch (IOException e) {e.printStackTrace();}}}).start();new Thread(new Runnable() {Overridepublic void run() {try {byte []arr new byte[128];while (pipedInputStream.read(arr) ! -1) {System.out.println(Arrays.toString(arr));}pipedInputStream.close();} catch (IOException e) {e.printStackTrace();}}}).start();JavaIO 字节和字符数组
不仅可以用来做缓存数据的临时存储空间同时也可以作为数据来源或者写入目的
//字符数组和字节数组在io过程中的作用
public void test4() {//arr和brr分别作为数据源char []arr {a,c,d};CharArrayReader charArrayReader new CharArrayReader(arr);byte []brr {1,2,3,4,5};ByteArrayInputStream byteArrayInputStream new ByteArrayInputStream(brr);
}序列化和反序列化
通过ObjectInputStream转换InputStream为Object
ObjectInputStream input new ObjectInputStream(new FileInputStream(object.data));
MyClass object (MyClass) input.readObject();
input.close();流的缓冲
BufferedReader为字符输入流提供缓冲区可以提高许多IO处理的速度默认为8KBBufferedInputStream为原始字节输入流提供缓冲区可以提高许多IO处理的速度 Testpublic void BufferedStreamTest() throws FileNotFoundException {BufferedInputStream bis null;BufferedOutputStream bos null;try {//1.造文件File srcFile new File(爱情与友情.jpg);File destFile new File(爱情与友情3.jpg);//2.造流//2.1 造节点流FileInputStream fis new FileInputStream((srcFile));FileOutputStream fos new FileOutputStream(destFile);//2.2 造缓冲流bis new BufferedInputStream(fis);bos new BufferedOutputStream(fos);//3.复制的细节读取、写入byte[] buffer new byte[10];int len;while((len bis.read(buffer)) ! -1){bos.write(buffer,0,len);// bos.flush();//刷新缓冲区}} catch (IOException e) {e.printStackTrace();} finally {//4.资源关闭//要求先关闭外层的流再关闭内层的流if(bos ! null){try {bos.close();} catch (IOException e) {e.printStackTrace();}}if(bis ! null){try {bis.close();} catch (IOException e) {e.printStackTrace();}}//说明关闭外层流的同时内层流也会自动的进行关闭。关于内层流的关闭我们可以省略.
// fos.close();
// fis.close();}}流的转换
通过InputStreamReader、OutputStreamWriter Testpublic void test1() throws IOException {FileInputStream fis new FileInputStream(dbcp.txt);
// InputStreamReader isr new InputStreamReader(fis);//使用系统默认的字符集//参数2指明了字符集具体使用哪个字符集取决于文件dbcp.txt保存时使用的字符集InputStreamReader isr new InputStreamReader(fis,UTF-8);//使用系统默认的字符集char[] cbuf new char[20];int len;while((len isr.read(cbuf)) ! -1){String str new String(cbuf,0,len);System.out.print(str);}isr.close();}标准输入输出流
System.in和System.out分别代表了系统标准的输入和输出设备 默认输入设备是键盘输出设备是显示器 System.in的类型是InputStream System.out的类型是PrintStream其是OutputStream的子类FilterOutputStream 的子类
BufferedReader br null;
InputStreamReader isr new InputStreamReader(System.in);
br new BufferedReader(isr);while (true) {System.out.println(请输入字符串);String data br.readLine();if (e.equalsIgnoreCase(data) || exit.equalsIgnoreCase(data)) {System.out.println(程序结束);break;
}字节流和字符流的区别
字节流处理字节和字节数组或二进制对象stream命名 字符流处理字符、字符数组或字符串Reader、Writer命名。
1、字节流在操作的时候本身是不会用到缓冲区内存的是与文件本身直接操作的而字符流在操作的时候是使用到缓冲区的2、字节流在操作文件时即使不关闭资源close方法文件也能输出但是如果字符流不使用close方法的话则不会输出任何内容说明字符流用的是缓冲区并且可以使用flush方法强制进行刷新缓冲区这时才能在不close的情况下输出内容字节流用于操作包含ASCII字符的文件字符流用于读取包含Unicode字符的文件对于英文字符文件字节流和字符流都可以用
序列化
序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程反序列化将字节对象或XML编码格式还原成完全相等的对象
public class 序列化和反序列化 {
//注意内部类不能进行序列化因为它依赖于外部类
Test
public void test() throws IOException {
A a new A();
a.i 1;
a.s a;
FileOutputStream fileOutputStream null;
FileInputStream fileInputStream null;
try {
//将obj写入文件
fileOutputStream new FileOutputStream(temp);
ObjectOutputStream objectOutputStream new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(a);
fileOutputStream.close();//通过文件读取obj
fileInputStream new FileInputStream(temp);
ObjectInputStream objectInputStream new ObjectInputStream(fileInputStream);
A a2 (A) objectInputStream.readObject();
fileInputStream.close();
System.out.println(a2.i);
System.out.println(a2.s);
//打印结果和序列化之前相同
} catch (IOException e)
{ e.printStackTrace();
} catch (ClassNotFoundException e)
{ e.printStackTrace(); } } }class A implements Serializable {int i;String s;
}序列化ID
反序列化的前提是序列化ID得相同Eclipse提供两种产生序列化ID的方法一种是属性名时间戳另一种是我们一般用1L表示。
// 虽然两个类的路径和功能代码完全一致但是序列化 ID 不同他们无法相互序列化和反序列化
public class A implements Serializable { private static final long serialVersionUID 1L; private String name; public String getName() { return name; } public void setName(String name) { this.name name; }
} public class A implements Serializable { private static final long serialVersionUID 2L; private String name; public String getName() { return name; } public void setName(String name) { this.name name; }
}序列化引擎会根据对象时候实现了Serializable接口类如果没有则抛NotSerializableException异常这是因为在序列化操作过程中会对类型进行检查要求被序列化的类必须属于Enum、Array和Serializable类型其中的任何一种。如果实现了则会创建ObjectOutputStream 对象绑定到输出流上扫描对象中static因为其为类的状态、 transient关键字的字段不对其进行序列化Object对象流不写入也不读出。如果对象有其他对象的引用则需要递归将引用对象也进行序列化如果要序列化的类有父类要想同时将在父类中定义过的变量持久化下来那么父类也应该集成java.io.Serializable接口父类没实现Serializable接口那么子类序列化时父类不会序列化。当反序列化变为对象时因为子类对象创建会先创建父类所以会调用父类的构造方法。子类对象的属性的值存在父类对象的属性的值为0或者为nullArrayList实现了java.io.Serializable接口,可以对它进行序列化及反序列化。但是其中数组elementData用来保存列表中的元素的是transient的正常不应该被序列化保存下来。
为什么ArrayList要通过重写writeObject 和 readObject 方法来实现序列化呢为什么数组elementData是transient的
ArrayList实际上是动态数组每次在放满以后自动增长设定的长度值如果数组自动增长长度设为100而实际只放了一个元素那就会序列化99个null元素。为了保证在序列化的时候不会将这么多null同时进行序列化ArrayList把元素数组设置为transient为什么要重写writeObject 和 readObject 方法前面说过为了防止一个包含大量空对象的数组被序列化为了优化存储所以ArrayList使用transient来声明elementData。但是作为一个集合在序列化过程中还必须保证其中的元素可以被持久化下来所以通过重写writeObject 和 readObject方法的方式把其中的元素保留下来。writeObject方法把elementData数组中的元素遍历的保存到输出流ObjectOutputStream中。readObject方法从输入流ObjectInputStream中读出对象并保存赋值到elementData数组中。序列化引擎Dubbo 框架中的 Hession、JDK 自带的 Serializable、跨语言的 Hessian、ProtoBuf、ProtoStuff