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 深入分析的更多相关文章

  1. Java web项目引用java项目,类型找不到

    Java web项目引用java项目,类型找不到 错误信息: java.lang.ClassNotFoundException: org.codehaus.jackson.map.ObjectMapp ...

  2. Java Web项目与Java项目的区别

    一.以下是我对Java Web项目和Java项目这两者的理解以及区别: 1.Java Web项目是基于Java EE类的:而Java项目是基于Java应用程序的. 2.Java Web项目是网页的编码 ...

  3. Java Web系列:Java Web 项目基础

    1.Java Web 模块结构 JSP文件和AXPX文件类似,路径和URL一一对应,都会被动态编译为单独class.Java Web和ASP.NET的核心是分别是Servlet和IHttpHandle ...

  4. java web项目和java项目的区别(看清IDE本质)

    想必大家在使用MyEclipse时对这两个概念不去深究.只知道是Java EE类的基本都是Web项目,而Java应用程序就是Java项目.而且很多人都愿意使用MyEclipse作为开发工具,且不说大家 ...

  5. java web mysql.jar java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

    java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 折腾了一上午,找到了这错误的原因.哎……悲剧! 确认包已经被导入web工程目录. 原来是 ...

  6. Java web项目中java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

    原来是tomcat找不到MYSQL JAR包的问题.后来又把mysql-connector-java-5.1.7-bin.jar导入到tomcat的lib目录下面就ok了,嘿…… 在java项目中,只 ...

  7. java web 学习笔记 - Java Bean

    1. Java Bean 是一个简单的 java 类,一般放在WEB-INF下的 classes目录下(如果没有则需要手工新建) 一个简单的Bean包括属性,getter ,setter方法,如果没有 ...

  8. java web项目,java类中获得WEB-INF路径

    private static String getWebInfPath() { URL url = 当前类.class.getProtectionDomain().getCodeSource().ge ...

  9. JAVA Coder 的《深入分析Java Web 技术内幕》读书笔记

    本文基于<深入分析Java Web 技术内幕> <深入分析Java Web 技术内幕>,作者是 许令波,电子工业出版社.本文只是记录书本当中的精彩部分,作个人回顾和技术分享,请 ...

  10. 五分钟学Java:如何才能学好Java Web里这么多的技术

    原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 系列文章介绍 本文是<五分钟学Java>系列文章的一篇 本系列文章主要围绕Java程序员必须掌握的核心技能,结合我个人三年 ...

随机推荐

  1. centos6.6 ftp 配置 修改默认端口等

    常规下21端口容易遭到别人的扫描.带来了一定程度的不安全.所以,最好的就是把21端口修改掉. 默认修改为6069 一.修改vsftp的配置文件 vi /etc/vsftpd/vsftpd.conf 在 ...

  2. "errcode":40001,"errmsg":"invalid credential, access_token is invalid or not latest hint: [d0tQ_02368635

    微信报错,避免多处使用appid与secret发送求

  3. [Java复习] 分布式高可用-Hystrix

    什么是Hystrix? Hystrix 可以让我们在分布式系统中对服务间的调用进行控制,加入一些调用延迟或者依赖故障的容错机制. Hystrix 的设计原则 对依赖服务调用时出现的调用延迟和调用失败进 ...

  4. YApi内部部署文档

    旨在为开发.产品.测试人员提供更优雅的接口管理服务.可以帮助开发者轻松创建.发布.维护 API 1.安装Node.js环境(7.6+) 1.官网下载适合的nodejs版本放置在/usr/package ...

  5. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_04-用户认证技术方案-SpringSecurityOauth2

    2.3 Spring security Oauth2认证解决方案 本项目采用 Spring security + Oauth2完成用户认证及用户授权,Spring security 是一个强大的和高度 ...

  6. python学习:python的常用功能示例2

    1. python 写入txt with open("douban.txt","w") as f: f.write("这是个测试!") fi ...

  7. DB2存储过程简单示例

    在这个示例中,我们将在DB2中创建一个名为DEMO1201的存储过程. 该存储过程的输入参数IN_NAME和IN_CREDITCARD,表示用户的姓名和身份证号. 该存储过程的作用是根据身份证号来新建 ...

  8. EasyNetQ使用(六)【多态发布和订阅,消息版本控制】

    你能够订阅一个接口,然后发布基于这个接口的实现. 让我们看下一个示例.我有一个接口IAnimal和两个实现Cat和Dog: public interface IAnimal { string Name ...

  9. in-place数据交换

    实现in-place的数据交换 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 经典的排序问题 问题描述 一个数组中包含两个已经排好序的子数组,设计一个in- ...

  10. 基于MSP430F2618的程控电压源

    基于MSP430F2618的程控电压源 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 系列博客说明:此系列博客属于作者在大三大四阶段所储备的关于电子电路设计 ...