I/O
磁盘I/O
应用程序访问文件有以下几种方式。
- 标准访问文件:调用read()接口时,操作系统检查内核的高速缓存是否有需要的数据,没有再从磁盘读取,然后缓存到缓存中。写入调用write()接口时,将数据从用户空间复制到内核空间,至于什么时候写入磁盘由操作系统决定,除非显示调用同步命令。
- 直接I/O:应用程序直接访问磁盘,如果每次都访问磁盘效率太低,通常会对热点数据进行应用程序缓存和预加载。
3.同步访问文件:对磁盘数据的访问都是同步的,只有完成了数据访问,系统才会得到成功的标志。性能较差,特定情景会使用。
4.异步访问文件:对磁盘数据进行请求后,线程去处理应用程序其他事情,而不阻塞等待,等磁盘返回数据,再继续处理下面的事情。提高了应用程序的处理效率,但访问磁盘的效率并没有提高。
Java访问磁盘文件
Java里的File并不代表一个真实存在的文件对象,只有真正要读取这个文件时采用去检查这个File是否真实存在。在创建FileInputStream时会创建一个FileDescriptor对象,这个对象才是真正代表一个存在文件的描述。
Java序列化技术
Java序列化时将一个对象转化为二进制的字节数组从而达到转移和保存的目的,对象需实现Serializable。反序列化是将字节数组重新构造成对象,但是必须结合类模板。因此序列化数据并没有完整保存类的元数据。
网络I/O
TCP的连接与释放
连接:三次握手
①发起客户机A向B发起建立连接的请求。
②服务端B接收连接请求,向A发送同意请求信息。
③A收到同意请求信息,向B发出确认双方连接的信息。
释放:四次挥手
④A的信息发送完了,请求关闭A->B的连接。
⑤B接收到A的释放信息,确认A->B的释放,关闭A->B
B->A发送残余的信息
⑥B请求关闭B->A的连接
⑦A收到释放请求,同意释放,经过一段时间双方进入CLOSED。
JavaSocket
socket是建立在TCP/IP的基础之上的,应用程序通信通过端口来确定通信对象。
建立连接:服务机创建socketServer进行监听。客户机创建socket对象就是要与服务机完成三次握手协议。
数据传输:建立连接后各自拥有一个socket可获得InputStream和OutputStream,以字节流进行传输,is和os各自有一个缓冲区,如果缓冲区满,操作将会阻塞。
同步与异步
同步:A任务的完成依赖B任务,只有等待B任务完成,A才能完成,两个任务完成状态保持一致。
异步:A任务的完成不依赖B任务,只通知B任务要完成什么,A也立即执行,最终两个任务完成状态无法保持一致。
阻塞与非阻塞
阻塞与非阻塞是从CPU消耗来讲的。
阻塞:CPU停下来等一个慢操作完成后,CPU接着完成后续工作。
非阻塞:在慢操作执行时,CPU切去完成其他工作,等慢操作完成后,CPU再切回来完成后续工作。
编码
I/O中存在的编码:Reader是读字符的父类,InputStream是读字节的父类,InputStreamReader是关联两者的桥梁,两者转换过程中,不进行编码指定,将默认以本地的字符集进行编码,写操作类似。整个应用程序应该统一编码。
FileInputStream is = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(is,"UTF-8");
char[] buf = new char[64];
StringBuffer buffer = new StringBuffer();
int len = -1;
while((len = reader.read(buf)) != -1){
buffer.append(0,buf,len);
}
内存中存在的编码:
String s = "xxxx";
byte[] bytes = s.getBytes("UTF-8");
String ss = new String(bytes,"UTF-8");
UTF-8是较理想的中文编码方式。
URL中的编码:对于get请求,URL中的PathInfo和QueryString编码可能是不一样的,Tomcat对请求就行解码的字符集是在server.xml规定的,没有定义将默认按iso-8859-1解码,尽量使用ASCII字符。
<Connector URIEncoding="UTF-8"/>//有中文最好设置成UTF-8
POST提交的数据是放在请求体中的,Tomcat会按照请求体重的Content-Type进行解码,一般不会出现问题,也可以自己设置解码的字符集。
request.setCharsetEncoding(charset);
//取参数 getParameter...