Java Web 深入分析(4) Java IO 深入分析
I/O问题可以说是现在海量数据时代下 ,I/O大部分web系统的瓶颈。我们要了解的java I/O(后面简称为(IO))
- IO类库的基本结构
- 磁盘IO的工作机制
- 网络IO的工作机制
- NIO的工作方式
- 同步异步、阻塞非阻塞的区别
- IO优化技巧
IO类库的基本结构
字节流InputStream
提供public abstract int read() throws IOException;
public int read(byte b[]) throws IOException
public int read(byte b[], int off, int len) throws IOException3个读取方法
字节流OutputStream
提供public abstract void write(int b) throws IOException
public void write(byte b[]) throws IOException
public void write(byte b[], int off, int len) throws IOException
public void flush() throws IOException 4个输出方法
总结:不细说如何使用,关键流 可以组合使用,然后要么写到磁盘,要么写到网络,其实写网络也是写文件,不过会有特殊处理,就是让操作系统通过 传输到其他地方。
字符流Writer
Writer提供public void write(String str, int off, int len) throws IOException
public Writer append(CharSequence csq) throws IOException
abstract public void flush() throws IOException 等方法
字符流Reader
Writer提供public int read(java.nio.CharBuffer target) throws IOException
abstract public int read(char cbuf[], int off, int len) throws IOException;
public long skip(long n) throws IOException 等方法
总结:不管是网络还是磁盘传输,最小的存储单元都是字节,而不是字符,转换存在着耗时和烦人的编码问题,所以Java提供了字符流,注意无论是字符还是字节流都有共同的方法那就是close()方法
字节和字符的转换:InputStreamReader和OutPutStreamWriter
上图就是字符解码的过程,举例来说:假设你用FileReader去读取文件,FileReader继承了InputStreamReader,实际上就是读取文件流,然后通过StreamDecoder解码成了char,然后大多数情况下是默认的系统字符集Charset,同理字符编码类似,如下图
磁盘IO的工作机制
标准文件访问方式:读取先读高速缓存,若无则取磁盘;写入就是先将用户地址空间数据搬移到系统高速缓存块,然后有操作系统决定何时写入物理磁盘。
直接IO的方式:应用程序直接从磁盘读取数据,经典的就是数据库管理系统,数据库系统明确知道热点数据,会提前加载到内存中。通常是直接io和异步io结合使用。
同步访问件方式:顾名思义就是数据读写都是同步操作,与标准文件访问方式不同,只有数据真正写入到磁盘才会返回给应用程序写入成功标志。通常用于数据安全性较高的场景,也采用硬件定制的方式。
异步访问文件方式:访问数据的线程发出请求后并不是阻塞等待而是继续下面的操作。提高的是应用程序效率而不是访问文件的效率。
内存映射访问方式:查询系统将一块内存区域与磁盘文件关联起来,当需要访问磁盘数据改为访问高速缓存数据,减少从高速缓存加载硬盘数据,又去复制到程序内存的操作。
网络IO的工作方式
下面演示C/S socket udp nio
- 服务端
package ocr.test;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(10086);//创建serversocket 并绑定端口 10086 1024-65535之间,因为0-1024间有许多操作系统重要端口
System.out.println(">>>>>>>>>>>服务器已经启动!");
Socket socket =server.accept();//阻塞进程等待着 客户端连接
InputStream is =socket.getInputStream();//得到输入流
InputStreamReader isr = new InputStreamReader(is); //字符字节转换流
BufferedReader br = new BufferedReader(isr);//得到缓冲流
String msg = "";
while((msg=br.readLine() )!= null){
System.out.println("服务器:已经接收到客户端信息="+msg);
}
OutputStream os=socket.getOutputStream();//
PrintWriter pw = new PrintWriter(os);//
pw.write("欢迎客户端"+socket.getLocalAddress());
pw.flush();//刷新数据流
br.close();
isr.close();
is.close();
socket.close();
server.close();
os.close();
pw.close();
}
}
- 客户端
package ocr.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class client {
public static void main(String[] args) throws IOException, Exception {
Socket socket = new Socket("localhost", 10086);
System.out.println(">>>>>>>>>>>客户端已经启动!");
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
osw.write("用户User密码123");
osw.flush();
socket.shutdownOutput();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String msg ="";
while((msg =br.readLine())!=null){
System.out.println("客户端:接收到服务器信息="+msg);
}
br.close();
isr.close();
is.close();
osw.close();
os.close();
socket.close();
}
}
- 测试效果:
- UDP通信
服务端:
package ocr.test;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(10086);
byte[] msg = new byte[1024];
DatagramPacket pocket = new DatagramPacket(msg, msg.length);
socket.receive(pocket);
String msgs = new String(msg, 0, msg.length);
System.out.println("服务器:已经接收到客户端信息="+msgs);
InetAddress address = pocket.getAddress();
int port = pocket.getPort();
byte[] sendmsg = ("欢迎您"+port).getBytes();
DatagramPacket pocket2 = new DatagramPacket(sendmsg, sendmsg.length, address, port);
socket.send(pocket2);
socket.close();
}
}
客户端:
package ocr.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class client {
public static void main(String[] args) throws IOException, Exception {
//客户端
//1、定义服务器的地址、端口号、数据
InetAddress address =InetAddress.getByName("localhost");
int port =10086;
byte[] data ="用户名:admin;密码:123".getBytes();
//2、创建数据报,包含发送的数据信息
DatagramPacket packet = new DatagramPacket(data,data.length,address,port);
//3、创建DatagramSocket对象
DatagramSocket socket =new DatagramSocket();
//4、向服务器发送数据
socket.send(packet);
//接受服务器端响应数据
//======================================
//1、创建数据报,用于接受服务器端响应数据
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2,data2.length);
//2、接受服务器响应的数据
socket.receive(packet2);
String raply = new String(data2,0,packet2.getLength());
System.out.println("我是客户端,服务器说:"+raply);
//4、关闭资源
socket.close();
}
}
- java NIO:前面讲到的是BIO,无论是磁盘还是网络,都存在一个致命缺点就是:阻塞。当一个线程阻塞是,其他线程失去了CPU的使用权。于是我们需要nio这种通信方式。
客户端:给出一个方法!
public static void client(){
ByteBuffer buffer = ByteBuffer.allocate(1024);
SocketChannel socketChannel = null;
try
{
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("localhost",8080));
if(socketChannel.finishConnect())
{
int i=0;
while(true)
{
TimeUnit.SECONDS.sleep(1);
String info = "I'm "+i+++"-th information from client";
buffer.clear();
buffer.put(info.getBytes());
buffer.flip();
while(buffer.hasRemaining()){
System.out.println(buffer);
socketChannel.write(buffer);
}
}
}
}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}
finally{
try{
if(socketChannel!=null){
socketChannel.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
服务端:
package ocr.test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class ServerConnect
{
private static final int BUF_SIZE=1024;
private static final int PORT = 8080;
private static final int TIMEOUT = 3000;
public static void main(String[] args)
{
selector();
}
public static void handleAccept(SelectionKey key) throws IOException{
ServerSocketChannel ssChannel = (ServerSocketChannel)key.channel();
SocketChannel sc = ssChannel.accept();
sc.configureBlocking(false);
sc.register(key.selector(), SelectionKey.OP_READ,ByteBuffer.allocateDirect(BUF_SIZE));
}
public static void handleRead(SelectionKey key) throws IOException{
SocketChannel sc = (SocketChannel)key.channel();
ByteBuffer buf = (ByteBuffer)key.attachment();
long bytesRead = sc.read(buf);
while(bytesRead>0){
buf.flip();
while(buf.hasRemaining()){
System.out.print((char)buf.get());
}
System.out.println();
buf.clear();
bytesRead = sc.read(buf);
}
if(bytesRead == -1){
sc.close();
}
}
public static void handleWrite(SelectionKey key) throws IOException{
ByteBuffer buf = (ByteBuffer)key.attachment();
buf.flip();
SocketChannel sc = (SocketChannel) key.channel();
while(buf.hasRemaining()){
sc.write(buf);
}
buf.compact();
}
public static void selector() {
Selector selector = null;
ServerSocketChannel ssc = null;
try{
selector = Selector.open();
ssc= ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(PORT));
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);
while(true){
if(selector.select(TIMEOUT) == 0){
System.out.println("==");
continue;
}
Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while(iter.hasNext()){
SelectionKey key = iter.next();
if(key.isAcceptable()){
handleAccept(key);
}
if(key.isReadable()){
handleRead(key);
}
if(key.isWritable() && key.isValid()){
handleWrite(key);
}
if(key.isConnectable()){
System.out.println("isConnectable = true");
}
iter.remove();
}
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(selector!=null){
selector.close();
}
if(ssc!=null){
ssc.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
}
nio 更多参考:
[http://www.importnew.com/19816.html]{http://www.importnew.com/19816.html}
Java Web 深入分析(4) Java IO 深入分析的更多相关文章
- Java web项目引用java项目,类型找不到
Java web项目引用java项目,类型找不到 错误信息: java.lang.ClassNotFoundException: org.codehaus.jackson.map.ObjectMapp ...
- Java Web项目与Java项目的区别
一.以下是我对Java Web项目和Java项目这两者的理解以及区别: 1.Java Web项目是基于Java EE类的:而Java项目是基于Java应用程序的. 2.Java Web项目是网页的编码 ...
- Java Web系列:Java Web 项目基础
1.Java Web 模块结构 JSP文件和AXPX文件类似,路径和URL一一对应,都会被动态编译为单独class.Java Web和ASP.NET的核心是分别是Servlet和IHttpHandle ...
- java web项目和java项目的区别(看清IDE本质)
想必大家在使用MyEclipse时对这两个概念不去深究.只知道是Java EE类的基本都是Web项目,而Java应用程序就是Java项目.而且很多人都愿意使用MyEclipse作为开发工具,且不说大家 ...
- java web mysql.jar java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 折腾了一上午,找到了这错误的原因.哎……悲剧! 确认包已经被导入web工程目录. 原来是 ...
- Java web项目中java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
原来是tomcat找不到MYSQL JAR包的问题.后来又把mysql-connector-java-5.1.7-bin.jar导入到tomcat的lib目录下面就ok了,嘿…… 在java项目中,只 ...
- java web 学习笔记 - Java Bean
1. Java Bean 是一个简单的 java 类,一般放在WEB-INF下的 classes目录下(如果没有则需要手工新建) 一个简单的Bean包括属性,getter ,setter方法,如果没有 ...
- java web项目,java类中获得WEB-INF路径
private static String getWebInfPath() { URL url = 当前类.class.getProtectionDomain().getCodeSource().ge ...
- JAVA Coder 的《深入分析Java Web 技术内幕》读书笔记
本文基于<深入分析Java Web 技术内幕> <深入分析Java Web 技术内幕>,作者是 许令波,电子工业出版社.本文只是记录书本当中的精彩部分,作个人回顾和技术分享,请 ...
- 五分钟学Java:如何才能学好Java Web里这么多的技术
原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 系列文章介绍 本文是<五分钟学Java>系列文章的一篇 本系列文章主要围绕Java程序员必须掌握的核心技能,结合我个人三年 ...
随机推荐
- OpenJudge计算概论-找出第k大的数
/*================================================ 找出第k大的数 总时间限制: 1000ms 内存限制: 1000kB 描述 用户输入N和K,然后接 ...
- element ui组件的开始时间-结束时间验证
<el-date-picker v-model="seach.before" type="date" placeholder="开始时间&quo ...
- nmealib-0.5.3 问题 Build Error: undefined reference to `ceil'
When building on Ubuntu 12.x the build fails with the following error… gcc samples/generate/main.o - ...
- VS2015 osgEarth 编译
E:\OpenSourceGraph\CURL_install\includeE:\GDAL\includeE:\Geos\geos_3_5_install\includeE:\OpenSourceG ...
- LeetCode_189. Rotate Array
189. Rotate Array Easy Given an array, rotate the array to the right by k steps, where k is non-nega ...
- PostgreSQL学习笔记——事务
事务时需要在同一处理单元中执行的一系列更新处理的集合.通过使用事务,可以对数据库中的数据更新处理的提交和取消进行管理. 事务处理的终止指令包括COMMIT(提交处理)和ROLLBACK(取消处理)两种 ...
- caffe dropout解读
先上caffe dropout_layer.cpp源码,如下: // LayerSetUp DCHECK(threshold_ > 0.); DCHECK(threshold_ < 1.) ...
- C#登录SSH执行命令,下载文件
前言 批量登录SSH执行命令 ,把应急响应中的日志文件下载回来. 代码实现 Renci.SshNet编译出DLL,引用. using System; using System.Collections. ...
- linux中安装docker
uname -r yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ ...
- 共享文件word / excel /ppt 被用戶自己锁定无法编辑-解決方法
共享文件word / excel /ppt 被用戶自己鎖定無法編輯,但用戶嘗試過關閉所有文件和重啓過系統,依然無法編輯. 搜到解決方法: Just in case someone looking fo ...