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. 记一次被DDoS敲诈的历程 糖果LUA FreeBuf 今天 0x01 背景

    记一次被DDoS敲诈的历程 糖果LUA FreeBuf 今天 0x01 背景

  2. 环境初始化 Build and Install the Apache Thrift IDL Compiler Install the Platform Development Tools

    Apache Thrift - Centos 6.5 Install http://thrift.apache.org/docs/install/centos Building Apache Thri ...

  3. [Java复习] 分布式事务 Part 2

    分布式事务了解吗?如果解决分布式事务问题的? 面试官心里: 只要聊到你做了分布式系统,必问分布式事务,起码得知道有哪些方案,一般怎么来做,每个方案的优缺点是什么. 为什么要有分布式事务? 分布式事务实 ...

  4. linux服务器下安装phpstudy 如何命令行进入mysql

    配置了phpstudy 可是进不去mysql 老是报-bash: mysqld: command not found 解决方法:在linux环境下运行:ln -s /phpstudy/mysql/bi ...

  5. Elasticsearch .net 记录-1

    简介 ElasticSearch是一个开源的分布式搜索引擎,具备高可靠性,支持非常多的企业级搜索用例.像Solr4一样,是基于Lucene构建的.支持时间时间索引和全文检索.官网:http://www ...

  6. 30分钟让你学会 Spring事务管理属性

    Spring是一个Java开源框架,是为了解决企业应用程序开发复杂性由Rod Johnson创建的.框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开 ...

  7. Sybase数据库网页数据维护工具

    Sybase是优秀的数据库产品,在银行,政务等行业广泛使用, 现在TreeSoft数据库管理系统已支持Sybase了,直接在浏览器中就可以操作查看Sybase数据了,十分方便.        Tree ...

  8. OneNote2016代码高亮插件的安装与使用

    OneNote2016代码高亮插件的安装与使用 使用效果 我觉得CSDN和博客园上面的许多讲解都不是很清晰,最后还是我自己弄好的.这里分享一下: 第一步要确认自己OneNote的版本是32位的还是64 ...

  9. 小程序使用mpvue框架无缝接入Vant Weapp组件库

    有美团开源出的mpvue以其vue的语法和良好的开发效率再搭配上用户体验良好的UI组件无疑是定制化微信小程序的开发方式,然而由于mpvue是对微信原生开发的再次封装,这也为我们引入UI组件添加了不少麻 ...

  10. VisualStudioCode网页开发常用插件

    VS下载链接 提取码:usx8 VsCode扩展功能强大,在于他可以安装各种各样的插件来辅助开发.下面是我初学前端时常用的vscode开发插件 Chinese 汉化 Beautify 格式化javas ...